在C#中处理DBNull

And*_*eas 38 c# dbnull datareader

有没有更好/更清洁的方法来做到这一点?

int stockvalue = 0;
if (!Convert.IsDBNull(reader["StockValue"]))
    stockvalue = (int)reader["StockValue"];
Run Code Online (Sandbox Code Playgroud)

Phi*_*ert 59

最短的(恕我直言)是:

int stockvalue = (reader["StockValue"] as int?) ?? 0;
Run Code Online (Sandbox Code Playgroud)

说明:

  • 如果reader ["StockValue"]的类型为int,则返回值,并且"??" 运算符将返回结果
  • 如果reader ["StockValue"]不是int类型(例如DBNull),则返回null,并返回"??" 运算符将返回值0(零).

  • 但是使用显式的拆箱转换`int x =(int)obj`,当列的类型改变时,你的代码会中断,允许你将它修正为`double x =(double)obj`; @JohnSaunders提出一个红旗是正确的,因为`as int?`方法会默默地吞下这个变化; 如果有人注意到零值不存在,那么你只能抓住它. (3认同)
  • @Philippe:如果列的类型更改为Double或其他什么会发生什么? (2认同)
  • @John:它会返回0.但是不管你选择什么解决方案,如果一个列改变了数据类型,你就搞砸了,除非你调用Convert.ToInt32()或其他东西. (2认同)

Chr*_*sic 28

我处理这个的方式是

int? stockvalue = reader["StockValue"] as int?;
Run Code Online (Sandbox Code Playgroud)

非常简单,干净,一线.如果由于某种原因我绝对不能有一个空值(我发现通常不好推理,因为我宁愿知道一个值是否有意义,或者它是否为一个原始类型的单元化)我会这样做:

int stockvalue = (reader["StockValue"] as int?).GetValueOrDefault(-1);
Run Code Online (Sandbox Code Playgroud)


Viv*_*vek 11

几天前我写了一个扩展方法.通过使用它你可以做到:

int? stockvalue = reader.GetValue<int?>("StockValue");
Run Code Online (Sandbox Code Playgroud)

这是扩展方法(根据您的需要进行修改):

public static class ReaderHelper
{
    public static bool IsNullableType(Type valueType)
    {
        return (valueType.IsGenericType &&
            valueType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)));
    }

    public static T GetValue<T>(this IDataReader reader, string columnName)
    {
        object value = reader[columnName];
        Type valueType = typeof(T);
        if (value != DBNull.Value)
        {
            if (!IsNullableType(valueType))
            {
                return (T)Convert.ChangeType(value, valueType);
            }
            else
            {
                NullableConverter nc = new NullableConverter(valueType);
                return (T)Convert.ChangeType(value, nc.UnderlyingType);
            }
        }
        return default(T);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我非常喜欢C#,并且在一个地方或2中有类似的代码,但是我们绝对需要编写这样的代码.我希望随着DLR的不断进步,我们将永远不需要像这样编写代码进行类型争论. (2认同)

Dig*_*der 10

int? stockvalue = (int?)(!Convert.IsDBNull(result) ? result : null);
Run Code Online (Sandbox Code Playgroud)

一种可能的解决方案,以确保DBNull能够传递给您的代码.对于我们的小组,作为最佳实践,我们尝试不允许数据库中的NULL列,除非确实需要它.编码处理它有更多的开销,有时只是重新思考问题使得它不是必需的.


kem*_*002 7

是的,您可以使用int? 这种方式,您可以使用默认值null而不是0.由于stockvalue的结果可能为0,因此不会混淆数据库是0还是null.例如像这样(可以为空)我们有一个默认初始化-1来表示没有赋值.就个人而言,我认为这有点危险,因为如果您忘记将其设置为-1,则存在数据损坏问题,实际上很难追查.

http://msdn.microsoft.com/en-us/library/2cf62fcy(VS.80).aspx

int? stockvalue = null;

if (!Convert.IsDBNull(reader["StockValue"]))
    stockvalue = (int)reader["StockValue"];

//Then you can check 

if(stockValue.HasValue)
{
  // do something here.
}
Run Code Online (Sandbox Code Playgroud)

  • +1表示要使用的正确数据类型.但是,IIRC,`DBNull`仍然需要通过一些检查转换为`null`. (2认同)

Joh*_*ers 6

虽然引用方便reader["StockValue"],但效率不高.它也不是强类型的,因为它返回类型object.

相反,在您的代码中,执行以下操作:

int stockValueOrdinal = reader.GetOrdinal("StockValue");
int? stockValue = reader.IsDbNull(stockValueOrdinal) ?
    null : 
    reader.GetInt32(stockValueOrdinal);
Run Code Online (Sandbox Code Playgroud)

当然,最好一次获得所有的序数,然后在整个代码中使用它们.

  • @Philippe:抛出异常是_precisely_如果列类型改变而代码没有,代码应该做什么.当严重错误时返回零是一个非常糟糕的主意. (2认同)