Подтвердить что ты не робот

Является ли "ReferenceEquals (myObject, null)" лучше, чем "myObject == null"?

У меня есть сотрудник, который поклонник написания своих нулевых проверок следующим образом:

if (!ReferenceEquals(myObject, null))

Я, с другой стороны, считаю, что этот синтаксис громоздкий для чтения и предпочтения:

if (myObject != null)

Я нашел несколько статей и вопросов, обсуждая достоинства ReferenceEquals в отношении перегрузки оператора, но вне сценария перегрузки оператора, есть ли какая-либо польза для ReferenceEquals vs ==?

4b9b3361

Ответ 1

но вне сценария перегрузки оператора, есть ли какая-либо польза для ReferenceEquals vs ==?

Нет - единственное преимущество (и я бы утверждать, что это не так много), чтобы явно использовать Object.ReferenceEquals было бы то, что он никогда не будет использовать перегруженный оператор равным. В неперегруженном случае оператор == > определяется как "возвращает true, если его два операнда относятся к одному и тому же объекту" для всех "ссылочных типов, отличных от строки" , Таким образом, его эквивалент (при условии, что он не перегружен).

Я лично рекомендую использовать второй синтаксис и нахожу его более удобным для нулевой проверки. Я также утверждаю, что любая перегруженная operator== также должна обеспечивать надлежащую проверку против null, а в случае, когда она не была по какой-либо причине (что было бы странно), вероятно, будет определенное обоснование этого решения из-за чего вы захотите использовать перегрузку, а не ReferenceEquals.

Ответ 2

С помощью С# 7 вы можете использовать:

if ( !(myObject is null) )

Это эквивалентно

if (!ReferenceEquals(myObject, null))

Ответ 3

Хорошо, если кто-то должен переопределить операторы == or! =, они могут заставить их делать все, что им нужно. Возможно, даже он сделает что-то реальное, например, return true; или return false;. Кроме того, если есть перегруженный оператор, есть приличная вероятность, что он не будет работать так же хорошо, как ReferenceEquals (не гарантируется, и, вероятно, это мало чем важно, но все же).

Сказав это, поскольку с любой разумной реализацией любого перегруженного оператора это вряд ли будет проблемой вообще. Я лично не использую ReferenceEquals, если у меня нет веских причин не использовать оператор == для этого типа или в этом конкретном экземпляре.

Ответ 4

В терминах нулевых проверок они должны всегда возвращать те же результаты. Если ненулевая ссылка когда-либо равна нулю (даже при использовании шаблона Null Object), независимо от того, использовались ли операции ReferenceEquals или ==, это очень плохо. Таким образом, в этом сценарии я использовал бы ==/! =.

Я бы сказал, что если оператор == был перегружен, использование ReferenceEquals может быть немного быстрее. Первое, что нужно перегрузить ==, - это увидеть, указывают ли две переменные на один и тот же объект, поэтому в случае перегруженного оператора вы получите дополнительный фрейм в стеке вызовов. Использование ReferenceEquals также гарантирует, что выполняется только проверка.

Я бы вообще использовал ==/!= практически в любом другом сценарии. Вся идея состоит в том, что оператор определяет "равенство"; это не всегда ссылочный (на самом деле, большинство сложных объектов следует сравнивать структурно для равенства, они равны, если их члены равны). Объект, теоретически, знает, как лучше сравнивать себя с другим объектом, для равенства, относительного порядка и т.д., И поэтому вместо того, чтобы жестко кодировать очень конкретную и, возможно, неправильную логику, вы должны использовать объектно-ориентированный характер языка для пусть объект скажет вам, равен ли он чему-либо еще или нет.

Ответ 5

ReferenceEquals могут быть немного быстрее. Как упоминалось ранее, он гарантирует, что перегруженный оператор Equals не будет вызван. Также ReferenceEquals обеспечивает только одно сравнение, а не возможно 2 в зависимости от реализации перегруженного оператора Equals. Хотя очень вероятно, что перегруженный оператор сам использует ReferenceEquals в качестве первого оператора.

Я лично использую ReferenceEquals, но только в тех местах, где я действительно настраиваю, чтобы выжать последние тактовые циклы (места, которые, возможно, называются миллионы раз в секунду). Или когда у меня нет контроля над типом, как в случае с дженериками.... Но опять же, только когда производительность действительно критическая.

Ответ 6

Тег VB.NET, вероятно, не должен был включаться в этот вопрос, поскольку он не упоминается иначе, но для полноты Is эквивалентен Object.ReferenceEquals и поэтому всегда может использоваться вместо этого вызова.

Ответ 7

Итак, я хотел принять участие в этом разговоре, хотя ему и миллион лет.

Допустим, мы хотим написать метод расширения, который проверяет наличие нуля. Мы могли бы сделать следующее:

public static bool IsNull<T>(this T value) where T : class, new()
{ 
   return value == null;
}

но этот код скучный.

Причина в том, что T должен быть классом. Почему? Потому что мы не можем сравнивать типы значений с нулем. Что делает написание приличного общего кода большой болью.

Кроме того, вы можете прикрепить один и тот же метод к объекту, и вам все равно, что это за объект.

public static bool IsNull(this object value)
{
   return object.ReferenceEquals(value, null);
}

Это открывает другие возможности, такие как, например, написание отказоустойчивых монад для Linq или того, что у вас есть - без фактического ограничения вашего общего кода.

Ответ 8

Действительно, очень поздний ответ - но я попал в статью, когда читал библиотеку EFCore, и наткнулся на этот метод...

В Microsoft.EntityFrameworkCore.Utilities есть класс Check, который использует эту логику для нулевой проверки....

        internal static class Check
    {
        [ContractAnnotation("value:null => halt")]
        public static T NotNull<T>([NoEnumeration] T value, [InvokerParameterName] [NotNull] string parameterName)
        {
#pragma warning disable IDE0041 // Use 'is null' check
            if (ReferenceEquals(value, null))
#pragma warning restore IDE0041 // Use 'is null' check
            {
                NotEmpty(parameterName, nameof(parameterName));

                throw new ArgumentNullException(parameterName);
            }

            return value;
        }