C# DBNull 和可为空类型 - 最干净的转换形式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1706405/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 20:07:46  来源:igfitidea点击:

C# DBNull and nullable Types - cleanest form of conversion

c#datatabletypesnullable

提问by

I have a DataTable, which has a number of columns. Some of those columns are nullable.

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

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

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

What, then, is the cleanest form of converting from a value in a DataRow, to a nullable variable.

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

Ideally, I would be able to do something like:

理想情况下,我将能够执行以下操作:

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

Edit: Turns out you CAN do this, the side effect being that if your Schema types arn't ints, then this is ALWAYS going to return null. The answer by Ruben of using dr.Field<int?>("A")ensures type mismatches don't silently fail. This, of course, will be picked up by thorough unit tests.

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

Instead I'm usually typing something along the lines of:

相反,我通常会输入以下内容:

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

This is a bunch more keystrokes, but more importantly, there's more room for someone to stuff something up with a wrong keystroke. Yes, a Unit Test will pick this up, but I'd rather stop it altogether.

这是更多的按键,但更重要的是,有人有更多的空间用错误的按键来填充某些东西。是的,单元测试会解决这个问题,但我宁愿完全停止它。

What is the cleanest, least error-prone pattern for this situation.

在这种情况下,最干净、最不容易出错的模式是什么?

采纳答案by Ruben Bartelink

The LINQ to DataSets chapter of LINQ in Actionis a good read.

LINQ in Action 的 LINQ to DataSets 一章很好读。

One thing you'll see is the Field<T>extension method, which is used as follows:-

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

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

Or

或者

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

Or

或者

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

回答by bniwredyc

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

回答by stepanian

Why not use LINQ? It does the conversion for you.

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

回答by Brannon

Extension methods!

扩展方法!

Something like the following:

类似于以下内容:

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

Use it like so:

像这样使用它:

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

or

或者

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

回答by KM?n

Following would work, safely:

以下将工作,安全:

Snip:

剪辑:

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

Usage:

用法:

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

回答by Robert Rossney

This is the purpose of the DataRowExtensionsclass in .NET 3.5, which provides static Field<T>and SetField<T>methods for round-tripping nullable (and non-nullable) data between the DataRowand .NET types.

这是DataRowExtensions.NET 3.5 中类的用途,它提供静态Field<T>SetField<T>方法,用于在DataRow和 .NET 类型之间往返可空(和不可空)数据。

int? fld = row.Field<int?>("ColumnA")

will set fldto nullif row["ColumnA"]contains DBNull.Value, to its value if it contains an integer, and throw an exception if it contains anything else. And on the way back,

将设置fldnullif row["ColumnA"]contains DBNull.Value,如果它包含一个整数则设置为它的值,如果它包含其他任何内容则抛出异常。而在回来的路上,

row.SetField("ColumnA", fld);

does the same thing in reverse: if fldcontains null, it sets row["ColumnA"]to DBNull.Value, and otherwise sets it to the value of fld.

反过来做同样的事情:如果fldcontains null,则设置row["ColumnA"]DBNull.Value,否则将其设置为 的值fld

There are overloads of Fieldand SetFieldfor all of the value types that DataRowsupports (including non-nullable types), so you can use the same mechanism for getting and setting fields irrespective their data type.

还有的过载Field,并SetField为所有的值类型的DataRow支持(包括非可空类型),所以你可以使用相同的机制来获取和设置领域,不论其数据类型。

回答by Nilesh S

   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();

回答by Chetan Mandhania

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

To call the function you could write

要调用您可以编写的函数

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