我目前正在使用此方法从DataReader读取数据 -
private T GetValue<T>(object obj)
{
if (typeof(DBNull) != obj.GetType())
{
return (T)obj;
}
return default(T);
}
Run Code Online (Sandbox Code Playgroud)
将上述方法称为 -
GetValue<int>(dataReader["columnName1"])
GetValue<string>(dataReader["columnName2"])
GetValue<float>(dataReader["columnName3"])
Run Code Online (Sandbox Code Playgroud)
但是,当columnName3具有7200000与错误一样的值时,这会失败
Invalid Cast Exception.
我正在考虑修改我的替换方法 -
return (T)obj;
Run Code Online (Sandbox Code Playgroud)
同
return (T)Convert.ChangeType(obj, typeof(T));
Run Code Online (Sandbox Code Playgroud)
但期待更好的方式,因为这种变化将涉及两次类型铸造.
有更好的想法吗?
谢谢!
通用方法的优点是可以减少很多代码膨胀,但否则,为每种数据类型编写自己的包装器将为您提供自定义处理的灵活性。而且,很可能您的数据库查询对性能的影响比对检索方式的影响大。
我建议您编写一组自己的扩展方法,而不要使用一种通用方法。将方法扩展IDataReader为您的好处是不会在整个对象子类型上传播方法。我不得不单独处理类型,因为各种连接器的行为特别是与Guid类型不同。同样,很难知道datareader是否读取了该值0或两种情况下DBNull何时返回0。可以说表中有一个带有空值的枚举字段。您为什么要把它作为第一个枚举阅读?
只需致电:
dataReader.GetInt("columnName1")
dataReader.GetString("columnName3")
dataReader.GetFloat("columnName3")
Run Code Online (Sandbox Code Playgroud)
以及方法:
public static int? GetInt(this IDataReader r, string columnName)
{
var i = r[columnName];
if (i.IsNull())
return null; //or your preferred value
return (int)i;
}
public static bool IsNull<T>(this T obj) where T : class
{
return (object)obj == null || obj == DBNull.Value;
}
Run Code Online (Sandbox Code Playgroud)
同样,
public static string GetString(this IDataReader r, string columnName)
{
}
public static float GetFloat(this IDataReader r, string columnName)
{
}
Run Code Online (Sandbox Code Playgroud)
如果您真的想要一个泛型函数,也可以拥有它。
public static T Get<T>(this IDataReader r, string columnName, T defaultValue = default(T))
{
var obj = r[columnName];
if (obj.IsNull())
return defaultValue;
return (T)obj;
}
Run Code Online (Sandbox Code Playgroud)
所以叫它
dataReader.Get<int>(1); //if DBNull should be treated as 0
dataReader.Get<int?>(1); //if DBNull should be treated as null
dataReader.Get<int>(1, -1); //if DBNull should be treated as a custom value, say -1
Run Code Online (Sandbox Code Playgroud)
就是说,该错误是因为您未按照注释中的说明使用正确的类型进行转换。我本可以进行内置DBNull检查,但是我避免避免从读取器多次读取数据,这是受到这种微优化的奇怪情况的启发
从 .NET Framework 4.5 开始
static class SqlReaderExtension
{
public static async Task<T> ReadAsync<T>(this SqlDataReader reader, string fieldName)
{
if (reader == null) throw new ArgumentNullException(nameof(reader));
if (string.IsNullOrEmpty(fieldName))
throw new ArgumentException("Value cannot be null or empty.", nameof(fieldName));
int idx = reader.GetOrdinal(fieldName);
return await reader.GetFieldValueAsync<T>(idx);
}
}
Run Code Online (Sandbox Code Playgroud)
进而
string result = await reader.ReadAsync<string>("FieldName");
Run Code Online (Sandbox Code Playgroud)