【问题标题】:When can a generic parameter never be null泛型参数何时不能为空
【发布时间】:2012-09-09 14:14:20
【问题描述】:

在一个通用的GetHashCode(T foo) 方法中,我检查foo 是否是null。 然而,我偶然发现了一个奇怪的 Resharper 警告。

在下面的代码中,foo 可以永远不是null吗?

private class FooComparer<T> : IEqualityComparer<T> where T: Foo
{
    public int GetHashCode(T foo)
    {
        // resharper warning:  "Expression is always false"
        if (Object.ReferenceEquals(null,foo)) return 0; 

        // ... calculate hash
    }
}

但据我所知,以下是完全合法的:

Foo foo = null;
var fooComparer = new FooComparer<Foo>();
int hash = fooComparer.GetHashCode(foo);

【问题讨论】:

  • 是的,您的代码完全合法。
  • Foo 是值还是引用类型?
  • Foo 是一个类,而不是一个结构

标签: c# generics null resharper language-specifications


【解决方案1】:

方法IEqualityComparer&lt;T&gt;.GetHashCode 的参数有契约[NotNull],因为它的实现会在null 作为参数提供时引发异常。

如果你想直接使用FooComparer&lt;T&gt;.GetHashCode 并且null 的异常安全作为它的参数,你可以注释如下:

public int GetHashCode([JetBrains.Annotations.CanBeNull] T foo)
{
    // resharper warning:  "Expression is always false"
    if (Object.ReferenceEquals(null,foo)) return 0; 

    // ... calculate hash
}

但必须改进对[Not-Null]-参数的分析。 http://youtrack.jetbrains.com/issue/RSRP-304111中的类似代码存在此错误

【讨论】:

    【解决方案2】:

    MSDN for IEqualityComparer&lt;T&gt;.GetHashCode Method 说:

    例外情况:

    ArgumentNullExceptionobj的类型是引用类型,objnull

    这似乎暗示使用null 参数调用GetHashCode&lt;T&gt;(T obj) 违反了IEqualityComparer&lt;T&gt; 的约定。

    我假设 Resharper 假设调用者遵守该合同,因此永远不会传入 null

    【讨论】:

    • 好点! MDSN 文档中似乎存在一些不一致之处,例如 this implementation of IEqulityComparer.GetHashCode 使用与我相同的空检查。
    • 我就像你一样实现我的GetHashCode(希望我避免ReferenceEquals,因为它会导致拳击)。对于GetHashCode,返回一个常量似乎是最干净的选择。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 1970-01-01
    • 2012-11-17
    • 1970-01-01
    相关资源
    最近更新 更多