Подтвердить что ты не робот

С# DBNull и nullable Types - самая чистая форма преобразования

У меня есть DataTable, который имеет несколько столбцов. Некоторые из этих столбцов имеют значение NULL.

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

Изменить. Оказывается, вы МОЖЕТЕ это сделать, побочным эффектом является то, что если ваши типы схем arn't ints, то это ВСЕГДА собирается вернуть null. Ответ Ruben на использование dr.Field<int?>("A") гарантирует, что несоответствия типов не будут терпеть неудачу. Это, конечно же, будет подхвачено тщательными модульными испытаниями.

Вместо этого я обычно печатаю что-то по строкам:

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

Это пучок больше нажатий клавиш, но что более важно, есть больше места для кого-то, чтобы что-то наделать с неправильным нажатием клавиши. Да, Unit Test выберет это, но я бы предпочел полностью его остановить.

Каков самый чистый, наименее подверженный ошибкам шаблон для этой ситуации.

4b9b3361

Ответ 2

Это назначение класса DataRowExtensions в .NET 3.5, который предоставляет статические методы Field<T> и SetField<T> для округления значений NULL (и не нулевых) между типами DataRow и .NET.

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

установит fld в null, если row["ColumnA"] содержит DBNull.Value, его значение, если оно содержит целое число, и генерирует исключение, если оно содержит что-либо еще. И на обратном пути,

row.SetField("ColumnA", fld);

делает то же самое в обратном порядке: если fld содержит null, он устанавливает row["ColumnA"] в DBNull.Value и в противном случае устанавливает его значение fld.

Существуют перегрузки Field и SetField для всех типов значений, поддерживаемых DataRow (включая типы, не содержащие NULL), поэтому вы можете использовать тот же механизм для получения и установки полей независимо от их типа данных.

Ответ 3

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

Ответ 4

Почему бы не использовать LINQ? Он делает конверсию для вас.

Ответ 5

Следующее будет работать безопасно:

Снип:

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

Ответ 6

Методы расширения!

Что-то вроде следующего:

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

Ответ 7

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

Ответ 8

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