【问题标题】:How to get the default value for a ValueType Type with reflection如何使用反射获取 ValueType 类型的默认值
【发布时间】:2011-10-27 10:30:27
【问题描述】:

如果我有一个值类型的泛型类型参数,并且我想知道一个值是否等于默认值,我会像这样测试它:

static bool IsDefault<T>(T value){
    where T: struct
    return value.Equals(default(T));
}

如果我没有泛型类型参数,那么似乎我必须使用反射。如果该方法必须适用于所有值类型,那么 有没有比我在这里做的更好的方法来执行这个测试? :

static bool IsDefault(object value){
   if(!(value is ValueType)){
      throw new ArgumentException("Precondition failed: Must be a ValueType", "value");
   }
   var @default = Activator.CreateInstance(value.GetType());
   return value.Equals(@default);  
}

在旁注中,关于评估 Nullable 结构,有什么我没有考虑的吗?

【问题讨论】:

  • 我觉得没问题。好在value is ValueType 测试也会检查null。 :)
  • 两个问题:1.为什么不用泛型方法? 2. 为什么不把第二个方法的参数设为ValueType,反正你就是要抱怨呢?
  • 或者if (!(value is ValueType)) return value == null;

标签: c# reflection struct default default-constructor


【解决方案1】:

我需要ValueType 作为参数来简化:

static bool IsDefault(ValueType value){
   var @default = Activator.CreateInstance(value.GetType());
   return value.Equals(@default);  
}

【讨论】:

  • cdhowie 的评论让我重新思考这个解决方案,因为它无法处理潜在的NullReferenceException。如果参数为空,请务必处理这种情况或抛出ArgumentNullException
【解决方案2】:

顺便说一句,有什么我没有考虑的吗? 关于评估 Nullable 结构?

是的,你错过了一些东西。通过将object 作为参数,您需要调用代码来框Nullable&lt;T&gt; 类型(将它们转换为null 或它们的T 值)。因此,如果您传递一个可空值,您的 is/throw 将抛出,因为 null 永远不会是值类型。

编辑: 正如@cdhowie 所说,您需要检查是否为空。这也适用于 Nullable 类型。

【讨论】:

  • 对可空结构体要考虑的另一件事是,没有办法区分例如一个值为 0 的 int 和一个值为 0 的 int?,尽管 0 是第一个类型的默认值,但不是第二个类型的默认值。
【解决方案3】:

我发现以下扩展方法很有用,适用于所有类型:

public static object GetDefault(this Type t)
{
    return t.IsValueType ? Activator.CreateInstance(t) : null;
}

public static T GetDefault<T>()
{
    var t = typeof(T);
    return (T) GetDefault(t);
}

public static bool IsDefault<T>(T other)
{
    T defaultValue = GetDefault<T>();
    if (other == null) return defaultValue == null;
    return other.Equals(defaultValue);
}

【讨论】:

  • 这在纯反射场景中似乎不起作用,在这种场景中你不知道两者的类型,进来的是一个对象。所以IsDefault 中的T 只是对象,.Equals 只是检查引用是否相等。至少在我的情况下,装箱的0 不等于Activator.CreateInstance(property.PropertyType),其中propertyTypeint
  • 我一直在尝试您的解决方案,但发现更短(我相信它也应该可以正常工作):public static object GetDefault&lt;T&gt;(T obj) { return default(T); }
【解决方案4】:

老问题,但接受的答案对我不起作用,所以我提交了这个(可能可以做得更好):

public static object GetDefault(this Type type)
{   
    if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
    {
        var valueProperty = type.GetProperty("Value");
        type = valueProperty.PropertyType;
    }

    return type.IsValueType ? Activator.CreateInstance(type) : null;
}

结果如下:

typeof(int).GetDefault();       // returns 0
typeof(int?).GetDefault();      // returns 0
typeof(DateTime).GetDefault();  // returns 01/01/0001 00:00:00
typeof(DateTime?).GetDefault(); // returns 01/01/0001 00:00:00
typeof(string).GetDefault();    // returns null
typeof(Exception).GetDefault(); // returns null

【讨论】:

  • 仅供参考,这就是答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-03
  • 1970-01-01
  • 2020-05-31
  • 1970-01-01
相关资源
最近更新 更多