比较一个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 }