Grozz
Grozz

Reputation: 8425

object.ReferenceEquals or == operator?

Why is ThrowIfNull implemented as:

    static void ThrowIfNull<T>(this T argument, string name) where T : class
    {
        if (argument == null)
        {
            throw new ArgumentNullException(name);
        }
    }

Wouldn't it be better rewritten as:

    static void ThrowIfNull<T>(this T argument, string name) where T : class
    {
        if (object.ReferenceEquals(argument, null))
        {
            throw new ArgumentNullException(name);
        }
    }

Pros: it helps avoiding confusing Equals overloads and probably makes the code more clear.

Any cons to that? There should be some.

Upvotes: 6

Views: 3476

Answers (3)

Jon Skeet
Jon Skeet

Reputation: 1500065

There's no difference between the two. You're confusing overriding Equals (which isn't called in either implementation) with overloading == (which won't be relevant in either snippet as overloading is performed at compile time, and the compiler doesn't know enough about T to use any specific overload).

Just to show what I mean:

static void ThrowIfFoo<T>(this T argument, string name) where T : class
{
    if (argument == "foo")
    {
        throw new Exception("You passed in foo!");
    }
}

Testing with:

"foo".ThrowIfFoo(); // Throws

string x = "f";
x += "oo"; // Ensure it's actually a different reference

x.ThrowIfFoo(); // Doesn't throw

ThrowIfFoo doesn't know that T will be a string - because that depends on the calling code - and the overload resolution is only performed when ThrowIfFoo is compiled. Therefore it's using the operator ==(object, object) rather than ==(string, string).

In other words, it's like this:

object foo1 = "foo";

string tmp = "f";
object foo2 = tmp + "oo";

Console.WriteLine(foo1.Equals(foo2)); // Prints True
Console.WriteLine(foo1 == foo2); // Prints false
Console.WriteLine((string) foo1 == (string) foo2); // Prints True

In the last line, the compiler knows it can use the overload of == because both operands have compile-time types of string.

Upvotes: 12

LukeH
LukeH

Reputation: 269328

The == operator is resolved at compile-time, not runtime, and since T is generic the compiler will use the implementation of == provided by object itself, which checks for reference equality.

This is exactly what object.ReferenceEquals does too: calls the == implementation provided by object.

Upvotes: 5

Bas
Bas

Reputation: 27085

This is a mostly cosmetics.

obj == null will do a reference check and return, so will Equals if the argument is null and it's not overriden in T. It would require a pretty wonky/malicious implementation to return true when one argument is null.

Upvotes: 1

Related Questions