可空类型是很好的东西,泛型也很不错。
但是当我们需要访问动态创建的可空类型,问题就来了。

看下面的代码

PropertyInfo propHasValue = typeof(int?).GetProperty("HasValue");
int? example = null;
bool hasValue = (bool)propHasValue.GetValue(example, null);
Console.WriteLine(hasValue);

 

按照我们的预期结果,输出应为 false;
但是,CLR 并未正常运行,而是抛出了 System.Reflection.TargetException,非静态方法需要一个目标。
咋一看,让人丈二和尚摸不着头脑,啥意思啊?

具体细节在 System.Nullable<T> 的 Equals 实现细节上。
这里附上 Reflector 取出的代码

public override bool Equals(object other)
{
    
if (!this.HasValue)
    {
        
return (other == null);
    }
    
if (other == null)
    {
        
return false;
    }
    
return this.value.Equals(other);
}

 

  意思是,如果可空类型实例的值为空,那么和 null 比较相等时,总是返回 true。
这是可空类型对比较语法的支持,在这里完成了对语言级别的 null 判断支持。
但是这样就对反射 API 造成了障碍,因为反射是直接调用对象复写后的 Equals 的,那么在反射中的后期绑定调用,将总是认为值为空的可空类型的实例为空(这句话真别扭)。
那么在动态调用中,如果调用的成员为 Nullable<T> 的非静态成员,并且 HasValue 为 false,总是会抛出 TargetException 异常。

   这个问题是相对的,从可空类型存在的意义上来看,重载 null 比较并没有错,这是 C# 中支持可空类型的语法的基础, 在大多数场景,这是没有问题的。
   但是在某些特殊的场景中,譬如动态取 Nullable<T> 的非静态成员,将毫无办法。
   至少,应该提供一个 object.RawEquals(object,object),该方法不受运算符重载影响。

  这应该算是一个 BUG,期待 CLR 在以后的版本中修正这个问题。

posted on 2007-11-12 18:21  Zealic  阅读(5081)  评论(23编辑  收藏  举报