C# 从DataReader读取数据的通用方法

C# 从DataReader读取数据的通用方法,c#,sqldatareader,C#,Sqldatareader,我目前正在使用此方法从DataReader读取数据- private T GetValue<T>(object obj) { if (typeof(DBNull) != obj.GetType()) { return (T)obj; } return default(T); } 与 但期待更好的方式,因为这一变化将涉及两次类型转换。 还有更好的主意吗 谢谢大家! 泛型方法的优点是可以减少大量的代码膨胀,但是为每种数据类型编写自己的包装

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

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

但期待更好的方式,因为这一变化将涉及两次类型转换。
还有更好的主意吗


谢谢大家!

泛型方法的优点是可以减少大量的代码膨胀,但是为每种数据类型编写自己的包装器可以让您灵活地进行自定义处理。最有可能的是,您的db查询对性能的影响要比检索模式明显

我建议您编写一套自己的扩展方法,而不是使用一种通用方法。在
IDataReader
上扩展方法的好处是不在整个对象子类型上传播方法。我不得不单独处理类型,因为各种连接器的行为不同,特别是在
Guid
type中。另外,对于这两种情况,当您返回
0
时,很难知道datareader是否读取值
0
DBNull
。假设表中有一个枚举字段的值为空。为什么要将其作为第一个枚举读取

只要打电话:

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 T Get<T>(this IDataReader r, string columnName, T defaultValue = default(T))
{
    var obj = r[columnName];      
    if (obj.IsNull())
        return defaultValue;

    return (T)obj;
}
public static T Get(此IDataReader r,字符串columnName,T defaultValue=default(T))
{
var obj=r[columnName];
if(obj.IsNull())
返回默认值;
返回(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
dataReader.Get(1)//if DBNull应被视为0
dataReader.Get(1)//if DBNull应被视为null
获取(1,-1)//如果DBNull应被视为一个自定义值,例如-1

也就是说,错误是因为您没有使用注释中指出的正确类型进行强制转换。我本可以使用内置的
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);
    }
}
静态类SqlReaderExtension
{
公共静态异步任务ReadAsync(此SqlDataReader读取器,字符串字段名)
{
如果(reader==null)抛出新的ArgumentNullException(nameof(reader));
if(string.IsNullOrEmpty(fieldName))
抛出新ArgumentException(“值不能为null或空。”,nameof(fieldName));
int idx=reader.GetOrdinal(字段名);
返回wait reader.GetFieldValueAsync(idx);
}
}
然后

string result = await reader.ReadAsync<string>("FieldName");
string result=wait reader.ReadAsync(“字段名”);

数据库中columnName3的数据类型是什么?您见过Linq to Dataset吗?@RQDQ,它是SQL Server数据类型“real”。我刚刚尝试在控制台应用程序中进行复制,代码如下:objectobjvalue=7200000;float floatValue=(float)objValue;//失败here@Daniel,Linq to Dataset现在不是选项:-(为什么希望将实数转换为字符串?这是一个有用的错误,因为它显示了此代码在现实世界中的用处。对于值类型,当DB中的值为null时返回默认值(T)也是一个等待发生的灾难。
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
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");