比较一个generics与空值可能是一个值或引用types?

public void DoFoo<T>(T foo) where T : ISomeInterface<T> { //possible compare of value type with 'null'. if (foo == null) throw new ArgumentNullException("foo"); } 

我故意只检查null,因为我不想限制ValueType等于它的default(T) 。 我的代码编译和工作就这么好(ReSharper抱怨,但不是CodeAnalysis)。 虽然我想知道:

  • 有没有更为标准的方法来处理这种情况?
  • 有没有可能由此产生问题?
  • 当我拨打电话并通过值types时,真正发生了什么?

我故意只检查null因为我不想限制ValueType等于它的default(T)

这是一个很好的见解,但不用担心,你已经覆盖在那里。 首先使用==比较T与default(T)是不合法的; 重载parsing不会find唯一的最佳==操作符。

当然,你可以用.Equals做比较,但是如果接收者为空,那么你就冒着崩溃的风险,这正是你试图避免的。

有没有更为标准的方法来处理这种情况?

不。比较为null是在这里做的正确的事情。

正如C#规范在第7.10.6节中所述:“ 即使T可以表示值types, x == null构造也是允许的,当T是值types时,结果被简单地定义为false ”。

有没有可能由此产生问题?

当然。 只是因为代码编译并不意味着它有你想要的语义。 写一些testing。

当我拨打电话并通过值types时,真正发生了什么?

这个问题是模棱两可的。 让我把它改为两个问题:

当我使用一个非空值types的types实参调用generics方法时,真正发生了什么?

抖动编译第一次调用的方法与该构造。 当抖动检测到空检查时,它将其replace为“false”,因为它知道不可空值的types将永远不会等于null。

当我用generics方法调用一个引用types的types参数,但是一个structtypes的参数时,真正发生了什么呢? 例如:

 interface IFoo : ISomeInterface<IFoo> {} struct SFoo : IFoo { whatever } ... DoFooInternal<IFoo>(new SFoo()); 

在这种情况下,抖动不能消除空检查,呼叫站点不能避免拳击。 SFoo实例将被装箱,并且将检查对装箱的SFoo的引用是否为空。

不,不会有任何问题,但如果您希望警告消失,则可以使用以下内容:

 public void DoFoo<T>(T foo) where T : ISomeInterface<T> { if (ReferenceEquals(foo, null)) throw new ArgumentNullException("foo"); } 

或者你可以做这样的事情:

 // when calling this with an actual T parameter, you have to either specify the type // explicitly or cast the parameter to T?. public void DoFoo<T>(T? foo) where T : struct, ISomeInterface<T> { if (foo == null) { // throw... } DoFooInternal(foo.Value); } public void DoFoo<T>(T foo) where T : class, ISomeInterface<T> { if (foo == null) { // throw... } DoFooInternal(foo); } private void DoFooInternal<T>(T foo) where T : ISomeInterface<T> { // actual implementation } 
    Interesting Posts