Daan Timmer
Daan Timmer

Reputation: 15047

Avoid == and != operators on generic type parameters, but can it compare with null?

According to the Constraints on Type Parameters (C# Programming Guide) documentation it says, and I quote:

When applying the where T : class constraint, avoid the == and != operators on the type parameter because these operators will test for reference identity only, not for value equality. This is the case even if these operators are overloaded in a type that is used as an argument. The following code illustrates this point; the output is false even though the String class overloads the == operator.

With the following example:

public static void OpTest<T>(T s, T t) where T : class
{
    System.Console.WriteLine(s == t);
}
static void Main()
{
    string s1 = "target";
    System.Text.StringBuilder sb = new System.Text.StringBuilder("target");
    string s2 = sb.ToString();
    OpTest<string>(s1, s2);
}

However, ReSharper (I've just started using the demo/trial version to see if it is any worth to me) gives a hint/tip to do null-checking of parameters like so:

public Node(T type, Index2D index2D, int f, Node<T> parent)
{
    if (type == null) throw new ArgumentNullException("type");
    if (index2D == null) throw new ArgumentNullException("index2D");
    if (parent == null) throw new ArgumentNullException("parent");
}

(T is constrained with where T : class, new())

Can I safely follow ReSharper without running into problems that the C# documentation is trying to tell me to avoid?

Upvotes: 6

Views: 397

Answers (5)

SWeko
SWeko

Reputation: 30872

I would say that this is OK.

null is kinda special, so you are not doing an actual comparison between two reference variables, you are just assuring that the reference variable is not a null reference.

Compare this with, for example, SQL. There you have a completely different syntax for comparing ( a = b) and for the null check (a is null). The guideline is that you should avoid the first, but the second is ok.

Upvotes: 1

Eric Lippert
Eric Lippert

Reputation: 659956

Yes.

Only a very strange implementation of the == operator would make x == null mean something other than ReferenceEquals(x, null). If you are using classes that have such a strange implementation of equality, you have bigger problems than it being inconsistent when checking for null using a generic type argument.

Upvotes: 7

Servy
Servy

Reputation: 203802

The documentation is telling you that == will use a reference comparison regardless of what the actual type of T is, even if it has overloaded the == operator. In many cases this isn't what users would expect.

In the case of the resharper code it's comparing the variable to null, which you want to be a reference comparison, not a value comparison, so what the documentation is warning you of is the correct behavior here.

You could however make it a bit more explicit by writing something like this, just to be clearer:

if(object.ReferenceEquals(type, null))//...

Upvotes: 4

Tim S.
Tim S.

Reputation: 56536

Yes, it's generally ok to assume that null is a special case, and that it's okay to do == or != on it. This is due, in part at least, to the fact that the recommendation for overriding Equals says that x.Equals(null) should be false.

If you didn't have the T : class constraint, it'd be a different story, since you'd see some possibly-unexpected behavior for structs and nullable structs (you might want to do default(T) instead of null there).

And if you want to be explicit that yes, you know you're comparing the reference to null, you can always use object.ReferenceEquals(x, null) (I'd just go with ==/!=, though).

Upvotes: 2

evanmcdonnal
evanmcdonnal

Reputation: 48076

Yes, that is fine. The documentation says not to compare two parameters because you're doing a reference comparison. The code ReSharper suggests is just ensuring the reference you've been passed is not null so that is safe to do.

In my opinion the main reason the C# docs recommend you don't do that is because if for example you do == with two strings that were passed as T1 and T2 it will do a reference comparison. Any other time you do stringA == stringB it will do a value comparison with the overload in the string class. It's really just warning against doing these types of comparisons because the operator overload that would normally be used (if you used that operator on two types declared in local scope) is not.

Upvotes: 7

Related Questions