7

我目前正在使用这种方法从 DataReader 读取数据 -

private T GetValue<T>(object obj)
{
    if (typeof(DBNull) != obj.GetType())
    {
        return (T)obj;
    }
    return default(T);
}

将上述方法称为 -

GetValue<int>(dataReader["columnName1"])
GetValue<string>(dataReader["columnName2"])
GetValue<float>(dataReader["columnName3"])

但是,当columnName37200000与错误一样时,这会失败
Invalid Cast Exception.

我正在考虑修改我的方法来替换 -

return (T)obj;

return (T)Convert.ChangeType(obj, typeof(T));

但期待更好的方法,因为此更改将涉及两次类型转换。
有更好的想法吗?

谢谢!

4

2 回答 2

4

通用方法的优点是可以减少大量代码膨胀,但另外为每种数据类型生成自己的包装器可以让您灵活地进行自定义处理。与检索模式相比,您的数据库查询很可能对性能产生显着影响。

我建议您编写一组自己的扩展方法,而不是使用一种通用方法。扩展方法IDataReader给您带来的好处是不会在整个对象子类型上传播方法。我不得不单独处理类型,因为各种连接器的行为不同,尤其是Guid类型。也很难知道 datareader 是否读取了该值0,或者DBNull您何时返回0这两种情况。假设您的表中有一个具有空值的枚举字段。为什么你会希望它被阅读为第一个枚举?

只需致电:

dataReader.GetInt("columnName1")
dataReader.GetString("columnName3")
dataReader.GetFloat("columnName3")

和方法:

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;
}

同样,

public static string GetString(this IDataReader r, string columnName)
{
}

public static float GetFloat(this IDataReader r, string columnName)
{
}

如果你真的想要一个通用函数,你也可以拥有它。

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;
}

所以叫它

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

也就是说,错误是因为您没有像评论中指出的那样使用正确的类型进行投射。我本可以使用内置DBNull检查,但我不会避免从阅读器中多次读取数据,灵感来自这个奇怪的微优化案例

于 2013-02-02T22:36:50.793 回答
1

从 .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);
    }
}

接着

string result = await reader.ReadAsync<string>("FieldName");
于 2016-07-12T08:44:54.703 回答