在通用方法中使用一个语句进行拆箱和转换

时间:2016-09-22 11:28:03

标签: c# generics casting boxing

我有一个小实用方法,如下所示:

/// <summary>
/// Replaces a DBNull value with the default of the type specified
/// </summary>
/// <typeparam name="T">Resulting type</typeparam>
/// <param name="p_this">Object to check for DBNull</param>
/// <returns>p_this if it is not DBNull.Value, else default(T)</returns>
public static T ReplaceDBNullWithDefault<T>(this object p_this)
{
  return p_this == System.DBNull.Value ? default(T) : (T)p_this;
}

在我的特定场景中,我正在从数据表中取出记录并使用弱类型从中获取特定字段,而我获得的特定字段是long正在盒装成object。重现这一点的一个例子如下:

var obj = 2934L;
int num = obj.ReplaceDBNullWithDefault<int>();

InvalidCastException(T)p_this失败。

我明白为什么,盒装的long无法直接投放到int,尝试这样做也会失败:

object myLong = 234L;
int myInt = (int)myLong;

然而,拆箱然后转换工作正常:

object myLong = 234L;
int myInt = (int)(long)myLong;

我如何在我的方法中解决这个问题?

2 个答案:

答案 0 :(得分:0)

你可以试试这个:

public static T ReplaceDBNullWithDefault<T>(this object p_this) where T : struct
{
    return 
        p_this == System.DBNull.Value 
            ? default(T) 
            : (T)Convert.ChangeType(p_this, typeof(T));
}

但是,如果您尝试将此函数应用于不可转换类型,则会出现异常。

因此,将值手动转换为已知类型可能会更好。

答案 1 :(得分:0)

您可以使用此方法:

/// <summary>
/// Replaces a DBNull value with the default of the type specified
/// </summary>
/// <typeparam name="T">Resulting type</typeparam>
/// <param name="value">Object to check for DBNull</param>
/// <param name="tryConvert">if true the object will be converted to the target type if possible, otherwise an InvalidCastException is raised</param>
/// <returns>p_this if it is not DBNull.Value, else default(T)</returns>
/// <exception cref="InvalidCastException">Thrown if the target type is incorrect and the value could not be converted to it</exception>
public static T ReplaceDbNullWithDefault<T>(this object value, bool tryConvert = true)
{
    if (value == System.DBNull.Value || value == null)
        return default(T);
    if (value is T)
        return (T) value;
    if(!tryConvert || !(value is IConvertible))
        throw new InvalidCastException($"Cannot convert {value.GetType()} to {typeof(T)}.");
    return (T)((IConvertible) value).ToType(typeof(T), null);
}