可以返回数据行中列的值并自动处理列值为 null 的可能性的单一方法

本文关键字:处理 null 可能性 方法 单一 返回 数据 | 更新日期: 2023-09-27 18:31:44

任何人都可以建议一个单一的方法,该方法可以返回数据行中列的值并自动处理列值为空的可能性。本质上,我试图提出一个通用解决方案,利用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# 不允许基于参数约束的方法重载

可以返回数据行中列的值并自动处理列值为 null 的可能性的单一方法

下面将为您提供从数据行返回的值,或者如果值为 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);
}

你总是可以制作你自己的 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();