4

データ行の列の値を返し、列の値が null になる可能性を自動的に処理できる単一のメソッドを誰でも提案できますか? 基本的に、DataRow 拡張メソッドを利用して DBNull 値を処理する一般的なソリューションを考え出そうとしていました。これまでの私の解決策は次のとおりです。

public static Nullable<T> SafeRead<T>(DataRow row, string fieldName) where T : struct
{
    if (row.HasColumn(fieldName))
    {
        return row.Field<Nullable<T>>(fieldName) ?? default(Nullable<T>);
    }
    else
        return default(Nullable<T>);
}

public static T SafeRead<T>(DataRow row, string fieldName) where T : class
{
    if (row.HasColumn(fieldName))
    {
        return row.Field<T>(fieldName) ?? default(T);
    }
    else
        return default(T);
}

しかし、C# ではパラメーターの制約に基づくメソッドのオーバーロードが許可されていないため、これは明らかにメソッドのあいまいさについて不平を言っています。

4

2 に答える 2

2

以下は、データ行から返される値、または値が DBNull.Value の場合は型のデフォルトを示します。フィールドが定義されていない場合、ArgumentException がスローされます。

using System;
using System.Data;

public static class DataAccess
{
    public static T GetValueOrDefault<T>(DataRow row, string fieldName)
    {
        if (!row.Table.Columns.Contains(fieldName))
        {
            throw new ArgumentException(
                string.Format("The given DataRow does not contain a field with the name \"{0}\".", fieldName));
        }
        else if (row[fieldName].Equals(DBNull.Value))
        {
            return default(T);
        }

        return row.Field<T>(fieldName);
    }
}

そして、ここにいくつかの簡単なテストがあります:

[TestMethod]
public void GetValueOrDefault_ValueType_Test()
{
    const string FieldName = "Column";
    const int Expected = 5;

    DataTable dataTable = new DataTable();
    dataTable.Columns.Add(FieldName, typeof(int));

    DataRow row = dataTable.Rows.Add(Expected);

    int actual = DataAccess.GetValueOrDefault<int>(row, FieldName);
    Assert.AreEqual(Expected, actual);
}

[TestMethod]
public void GetValueOrDefault_ValueType_DBNull_Test()
{
    const string FieldName = "Column";

    DataTable dataTable = new DataTable();
    dataTable.Columns.Add(FieldName, typeof(int));

    DataRow row = dataTable.Rows.Add(DBNull.Value);

    int actual = DataAccess.GetValueOrDefault<int>(row, FieldName);
    Assert.AreEqual(default(int), actual);
}

[TestMethod]
public void GetValueOrDefault_ReferenceType_Test()
{
    const string FieldName = "Column";
    object expected = new object();

    DataTable dataTable = new DataTable();
    dataTable.Columns.Add(FieldName, typeof(object));

    DataRow row = dataTable.Rows.Add(expected);

    object actual = DataAccess.GetValueOrDefault<object>(row, FieldName);
    Assert.AreEqual(expected, actual);
}

[TestMethod]
public void GetValueOrDefault_ReferenceType_DBNull_Test()
{
    const string FieldName = "Column";

    DataTable dataTable = new DataTable();
    dataTable.Columns.Add(FieldName, typeof(object));

    DataRow row = dataTable.Rows.Add(DBNull.Value);

    object actual = DataAccess.GetValueOrDefault<object>(row, FieldName);
    Assert.AreEqual(default(object), actual);
}
于 2012-04-18T18:00:48.993 に答える
0

Nullable の独自のろくでなしの実装をいつでも作成し、それを関数から返すことができます。

public class SafeValue<T>
{
    public T Value {get; set;}
    public bool HasValue
    {
        get
        {
            if(typeof(T).IsClass)
                return Value != null;
            else return true;
        }
    }
}

したがって、両方を次のように置き換えます。

public static SafeValue<T> SafeRead<T>(DataRow row, string fieldName)
{
    if (row.HasColumn(fieldName))
    {
        return new SafeValue<T>{ Value = row.Field<T>(fieldName)};
    }
    else
        return new SafeValue<T>();
}

そして使用法:

var val = SafeRead(row, "wah");

if(val.HasValue)
    //DoStuff();
于 2012-04-18T17:06:24.697 に答える