我想这样做:

myYear = record.GetValueOrNull<int?>("myYear"),

注意将可空类型作为泛型参数。

因为GetValueOrNull函数可以返回null,我的第一次尝试是:

public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName)
  where T : class
{
    object columnValue = reader[columnName];

    if (!(columnValue is DBNull))
    {
        return (T)columnValue;
    }
    return null;
}

但我现在得到的错误是:

类型'int?'必须是引用类型,以便在泛型类型或方法中使用它作为参数'T'

没错!Nullable<int>是一个结构体!所以我尝试将类约束改为结构约束(作为副作用不能再返回null):

public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName)
  where T : struct

现在是作业:

myYear = record.GetValueOrNull<int?>("myYear");

给出以下错误:

类型'int?'必须是一个非空值类型,以便在泛型类型或方法中使用它作为参数'T'

是否可以将可空类型指定为泛型参数?


当前回答

我知道这很老了,但这里有另一个解决方案:

public static bool GetValueOrDefault<T>(this SqlDataReader Reader, string ColumnName, out T Result)
{
    try
    {
        object ColumnValue = Reader[ColumnName];

        Result = (ColumnValue!=null && ColumnValue != DBNull.Value) ? (T)ColumnValue : default(T);

        return ColumnValue!=null && ColumnValue != DBNull.Value;
    }
    catch
    {
        // Possibly an invalid cast?
        return false;
    }
}

现在,你不关心T是值类型还是引用类型。只有当函数返回true时,您才能从数据库中得到一个合理的值。 用法:

...
decimal Quantity;
if (rdr.GetValueOrDefault<decimal>("YourColumnName", out Quantity))
{
    // Do something with Quantity
}

这种方法与int非常相似。TryParse("123", out MyInt);

其他回答

将返回类型更改为Nullable<T>,并调用具有非Nullable参数的方法

static void Main(string[] args)
{
    int? i = GetValueOrNull<int>(null, string.Empty);
}


public static Nullable<T> GetValueOrNull<T>(DbDataRecord reader, string columnName) where T : struct
{
    object columnValue = reader[columnName];

    if (!(columnValue is DBNull))
        return (T)columnValue;

    return null;
}

这可能是一个死线程,但我倾向于使用以下方法:

public static T? GetValueOrNull<T>(this DbDataRecord reader, string columnName)
where T : struct 
{
    return reader[columnName] as T?;
}

较短的方法:

public static T ValueOrDefault<T>(this DataRow reader, string columnName) => 
        reader.IsNull(columnName) ? default : (T) reader[columnName];

int返回0,int返回null ?

我认为您需要处理引用类型和结构类型。 我使用它将XML Element字符串转换为更有类型的类型。 您可以使用反射删除nullAlternative。 formatprovider将处理区域性相关的`。'或','分隔符,例如小数或整数和双精度数。 这可能有用:

public T GetValueOrNull<T>(string strElementNameToSearchFor, IFormatProvider provider = null ) 
    {
        IFormatProvider theProvider = provider == null ? Provider : provider;
        XElement elm = GetUniqueXElement(strElementNameToSearchFor);

        if (elm == null)
        {
            object o =  Activator.CreateInstance(typeof(T));
            return (T)o; 
        }
        else
        {
            try
            {
                Type type = typeof(T);
                if (type.IsGenericType &&
                type.GetGenericTypeDefinition() == typeof(Nullable<>).GetGenericTypeDefinition())
                {
                    type = Nullable.GetUnderlyingType(type);
                }
                return (T)Convert.ChangeType(elm.Value, type, theProvider); 
            }
            catch (Exception)
            {
                object o = Activator.CreateInstance(typeof(T));
                return (T)o; 
            }
        }
    }

你可以这样使用它:

iRes = helper.GetValueOrNull<int?>("top_overrun_length");
Assert.AreEqual(100, iRes);



decimal? dRes = helper.GetValueOrNull<decimal?>("top_overrun_bend_degrees");
Assert.AreEqual(new Decimal(10.1), dRes);

String strRes = helper.GetValueOrNull<String>("top_overrun_bend_degrees");
Assert.AreEqual("10.1", strRes);

我知道这很老了,但这里有另一个解决方案:

public static bool GetValueOrDefault<T>(this SqlDataReader Reader, string ColumnName, out T Result)
{
    try
    {
        object ColumnValue = Reader[ColumnName];

        Result = (ColumnValue!=null && ColumnValue != DBNull.Value) ? (T)ColumnValue : default(T);

        return ColumnValue!=null && ColumnValue != DBNull.Value;
    }
    catch
    {
        // Possibly an invalid cast?
        return false;
    }
}

现在,你不关心T是值类型还是引用类型。只有当函数返回true时,您才能从数据库中得到一个合理的值。 用法:

...
decimal Quantity;
if (rdr.GetValueOrDefault<decimal>("YourColumnName", out Quantity))
{
    // Do something with Quantity
}

这种方法与int非常相似。TryParse("123", out MyInt);