DataRow的通用字段getter

时间:2011-02-09 16:45:38

标签: c# generics ado.net extension-methods datarow

我尝试使用这种通用方法扩展DataRow对象:

public static T? Get<T>(this DataRow row, string field) where T : struct
{
  if (row.IsNull(field))
    return default(T);
  else
    return (T)row[field];
}

当T为intdecimaldouble等时,此功能正常。

但是当我尝试使用字符串时,我有这个错误:

  

“类型'字符串'必须是a   不可为空的值类型以便   在通用中将它用作参数'T'   类型或方法'System.Nullable'“

我该如何纠正?

我知道字符串不是结构,但如果字符串字段是DBNull,我不会返回null。

7 个答案:

答案 0 :(得分:6)

我认为这就是你想要的:

public static T? GetValue<T>(this DataRow row, string field) where T : struct
{
    if (row.IsNull(field))
        return new T?();
    else
        return (T?)row[field];
}

public static T GetReference<T>(this DataRow row, string field) where T : class
{
    if (row.IsNull(field))
        return default(T);
    else
        return (T)row[field];
}

答案 1 :(得分:5)

string不是struct,而是class。这就是错误消息告诉您的内容。只需删除约束。

也许您想查看DataRowExtensions

答案 2 :(得分:2)

不幸的是,除非您指定在进行呼叫时返回Nullable,否则您无法通过使用泛型来获取Nullable返回类型并支持引用类型

public static T Get<T>(this DataRow row, string field)
{
    if (row.IsNull(field))
        return default(T);
    else
        return (T)row[field];
}

当你打电话

var id = dr.Get<int?>("user_id");

我没有对此进行测试,只是把它扔到了这里。试一试。

编辑:

或者,如果你真的想将值类型转换为nullables并且仍然能够支持类似这样的引用类型

public static object GetDr<T>(this DataRow row, string field)
{
    // might want to throw some type checking to make 
    // sure row[field] is the same type as T
    if (typeof(T).IsValueType)
    {
        Type nullableType = typeof(Nullable<>).MakeGenericType(typeof(T));
        if (row.IsNull(field))
            return Activator.CreateInstance(nullableType);
        else
            return Activator.CreateInstance(nullableType, new[] { row[field] });
    }
    else
    {
        return row[field];
    }
}

但是,每次使用都需要演员

var id = dr.Get<string>("username") as string;
var id = (int?)dr.Get<int>("user_id");

然而,这并不像在通用类型参数中接受可空类型那样有效。

答案 3 :(得分:2)

ds.Tables[7].Rows.OfType<DataRow>().ToList().ForEach(f => tempList.Add(new MyEntity
{
  Id = int.Parse(f.ItemArray[0].ToString()),
  Title = f.ItemArray[1].ToString()
 }));

答案 4 :(得分:1)

正如Wes所指出的,你的问题是结构的约束。我希望扩展方法能够在没有约束的情况下工作......

啊,我现在看到了,你正在回归T?嗯,我不确定但你能定义方法的两个变体,一个约束到struct,另一个约束到class并返回T

答案 5 :(得分:1)

您有一个明确的条件阻止它使用字符串:

 where T : struct

System.String是一个类,而不是结构。如果您的目标是处理值类型和字符串,我会为字符串创建一个单独的方法,并将其单独留给其他类型。

答案 6 :(得分:1)

这样的事情怎么样?与您的示例不完全相同,但非常适用于引用类型,可空值的类型和不可为空的值类型:

int v = row.Get<int>("vvv");               // throws if column is null
int? w = row.Get<int?>("www");             // set to null if column is null
int x = row.Get<int?>("xxx") ?? -1;        // set to -1 if column is null
string y = row.Get<string>("yyy");         // set to null if column is null
string z = row.Get<string>("zzz") ?? ""    // set to "" if column is null

// ...

public static T Get<T>(this DataRow source, string columnName)
{
    if (source == null)
        throw new ArgumentNullException("source");

    if (columnName == null)
        throw new ArgumentNullException("columnName");

    if (columnName.Length < 1)
        throw new ArgumentException("Name cannot be empty.", "columnName");

    if (source.IsNull(columnName))
    {
        T defaultValue = default(T);
        if (defaultValue == null)
            return defaultValue;
    }

    // throws if the column is null and T is a non-nullable value type
    return (T)source[columnName];
}