object.ReferenceEquals или == оператор? - PullRequest
6 голосов
/ 19 августа 2011

Почему ThrowIfNull реализован как:

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

Не лучше ли переписать его как:

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

Плюсы: это помогает избежать путаницы Equals перегрузок и, возможноделает код более понятным.

Какие-нибудь минусы к этому?Там должно быть несколько.

Ответы [ 3 ]

12 голосов
/ 19 августа 2011

Нет разницы между этими двумя. Вы путаете переопределение Equals (которое не вызывается ни в одной из реализаций) с перегрузкой == (что не будет иметь значения в любом фрагменте, поскольку перегрузка выполняется в время компиляции, и компилятор не знает достаточно о T, чтобы использовать какую-либо конкретную перегрузку).

Просто чтобы показать, что я имею в виду:

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

Тестирование с:

"foo".ThrowIfFoo(); // Throws

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

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

ThrowIfFoo не знает, что T будет строкой - потому что это зависит от вызывающего кода - и разрешение перегрузки выполняется только , когда ThrowIfFoo компилируется . Поэтому он использует оператор ==(object, object) вместо ==(string, string).

Другими словами, это так:

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

В последней строке компилятор знает, что может использовать перегрузку ==, поскольку оба операнда имеют типов времени компиляции типов string.

5 голосов
/ 19 августа 2011

Оператор == разрешается во время компиляции, а не во время выполнения, и поскольку T является универсальным, компилятор будет использовать реализацию ==, предоставленную самой object, которая проверяет равенство ссылок.

Именно это и делает object.ReferenceEquals: вызывает реализацию ==, предоставленную object.

1 голос
/ 19 августа 2011

Это в основном косметика.

obj == null выполнит проверку и возврат ссылки, также будет Equals, если аргумент нулевой и он не переопределен в T. Требуется довольно странная / злонамеренная реализация для возврата true, когда один аргумент равен нулю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...