When can a generic parameter never be null
Asked Answered
C

2

5

In a generic GetHashCode(T foo) method, I check whether foo is null. However I just stumbled upon a strange Resharper warning.

In the following code, can foo never be 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
    }
}

However as far as I can tell, the following is perfectly legal:

Foo foo = null;
var fooComparer = new FooComparer<Foo>();
int hash = fooComparer.GetHashCode(foo);
Cardsharp answered 17/9, 2012 at 11:8 Comment(3)
Yes your code is perfectly legal.Hedvah
Is Foo a value or a reference type?Frazee
Foo is a class, not a structCardsharp
O
5

Method IEqualityComparer<T>.GetHashCode has contract [NotNull] for its parameter because it has implementations that throw an exception when null is provided as an argument.

If you want to use FooComparer<T>.GetHashCode directly and exception-safe for null as its argument, you can annotate it as follows:

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

    // ... calculate hash
}

Nevertheless analysis for [Not-Null]-parameters must be improved. This bug exists for similar code in http://youtrack.jetbrains.com/issue/RSRP-304111

Orphaorphan answered 17/9, 2012 at 14:43 Comment(0)
B
5

MSDN for IEqualityComparer<T>.GetHashCode Method says:

Exceptions:

ArgumentNullException The type of obj is a reference type and obj is null.

This seems to imply that calling GetHashCode<T>(T obj) with a null parameter violates the contract of IEqualityComparer<T>.

I assume Resharper assumes that callers adhere to that contract, and thus never pass in null.

Benignity answered 17/9, 2012 at 11:15 Comment(2)
Good point! There seems to be some inconsistency in the MDSN documentation, as for example this implementation of IEqulityComparer.GetHashCode uses the same null check as I do.Cardsharp
I for one implement my GetHashCode just like you do (Expect that I avoid ReferenceEquals, because it causes boxing). Returning a constant seems like the cleanest choice for GetHashCode.Benignity
O
5

Method IEqualityComparer<T>.GetHashCode has contract [NotNull] for its parameter because it has implementations that throw an exception when null is provided as an argument.

If you want to use FooComparer<T>.GetHashCode directly and exception-safe for null as its argument, you can annotate it as follows:

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

    // ... calculate hash
}

Nevertheless analysis for [Not-Null]-parameters must be improved. This bug exists for similar code in http://youtrack.jetbrains.com/issue/RSRP-304111

Orphaorphan answered 17/9, 2012 at 14:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.