C#DBNull和可空类型 - 最清晰的转换形式

时间:2009-11-10 08:34:18

标签: c# datatable types nullable

我有一个DataTable,它有很多列。其中一些列可以为空。

DataTable dt;  // Value set. 
DataRow dr;  // Value set. 

// dr["A"] is populated from T-SQL column defined as: int NULL 

那么,从DataRow中的值转换为可空变量的最干净的形式是什么。

理想情况下,我可以做类似的事情:

int? a = dr["A"] as int?; 

编辑 :原来你可以这样做,副作用是如果你的Schema类型没有整数,那么这总是会返回空值。 Ruben使用dr.Field<int?>("A")的答案确保类型不匹配不会无声地失败。当然,这将通过彻底的单元测试来获取。

相反,我通常会按照以下方式键入内容:

int? a = dr["A"] != DBNull.Value ? (int)dr["A"] : 0; 

这是一堆更多的击键,但更重要的是,有更多的空间让某人用错误的击键来填充内容。 是的,单元测试会选择它,但我宁愿完全停止它。

对于这种情况,最干净,最容易出错的模式是什么?

8 个答案:

答案 0 :(得分:54)

The LINQ to DataSets chapter of LINQ in Action读得很好。

您将看到的一件事是Field<T>扩展方法,其使用方法如下: -

int? x = dr.Field<int?>( "Field" );

或者

int y = dr.Field<int?>( "Field" ) ?? 0;

或者

var z = dr.Field<int?>( "Field" );

答案 1 :(得分:12)

这是.NET 3.5中DataRowExtensions类的目的,它提供静态Field<T>SetField<T>方法,用于在{之间绕过可空(和非可空)数据。 {1}}和.NET类型。

DataRow
如果int? fld = row.Field<int?>("ColumnA") 包含fld

会将null设置为row["ColumnA"],如果它包含整数,则将其设置为其值,如果包含任何其他内容,则抛出异常。在回来的路上,

DBNull.Value

反过来做同样的事情:如果row.SetField("ColumnA", fld); 包含fld,则会将null设置为row["ColumnA"],否则将其设置为DBNull.Value的值。

fld支持的所有值类型(包括非可空类型)都存在FieldSetField的重载,因此您可以使用相同的机制进行获取和设置字段与其数据类型无关。

答案 2 :(得分:4)

int? a = (int?)dr["A"]

答案 3 :(得分:1)

为什么不使用LINQ?它为您进行转换。

答案 4 :(得分:1)

以下会安全地工作:

<强>剪断:

public static class SqlDataReaderEx
{
    public static int TryParse(SqlDataReader drReader, string strColumn, int nDefault)
    {
        int nOrdinal = drReader.GetOrdinal(strColumn);
        if (!drReader.IsDbNull(nOrdinal))
            return drReader.GetInt32(nOrdinal);
        else
            return nDefault;
    }
}

<强>用法:

SqlDataReaderEx.TryParse(drReader, "MyColumnName", -1);

答案 5 :(得分:0)

扩展方法!

如下所示:

public static class DataRowExtensions
{
    public static Nullable<T> GetNullableValue<T>(this DataRow row, string columnName)
        where T : struct
    {
        object value = row[columnName];
        if (Convert.IsDBNull(value))
            return null;

        return (Nullable<T>)value;
    }

    public static T GetValue<T>(this DataRow row, string columnName)
        where T : class
    {
        object value = row[columnName];
        if (Convert.IsDBNull(value))
            return null;

        return (T)value;
    }
}

像这样使用它:

int? a = dr.GetNullableValue<int>("A");

string b = dr.GetValue<string>("B");

答案 6 :(得分:-1)

public static object GetColumnValue(this DataRow row, string columnName)
{
    if (row.Table.Columns.Contains(columnName))
    {
        if (row[columnName] == DBNull.Value)
        {
            if (row.Table.Columns[columnName].DataType.IsValueType)
            {
                return Activator.CreateInstance(row.Table.Columns[columnName].DataType);
            }
            else
            {
                return null;
            }
        }
        else
        {
            return row[columnName];
        }
    }
    return null;
}

要调用您可以编写的功能

var dt = new DataTable();
dt.Columns.Add("ColumnName");
....
Add rows in Datatable.
....
dt.Rows[0].GetColumnValue("ColumnName);

答案 7 :(得分:-4)

   Chart.data = new List < int ?> ();
   Chart.data = (from DataRow DR in _dtChartData.Rows
    select(int ? )((DR[_ColumnName] == DBNull.Value) ? (int ? ) null : (int ? ) DR[_ColumnName])).ToList();