2015-11-12 3 views
0

Я смотрел на справочник для .NET и реализации Equals для Int32, к примеру, выглядит следующим образом:Почему базовые типы C# 'Equals реализуют два раза?

public override bool Equals(Object obj) { 
    if (!(obj is Int32)) { 
     return false; 
    } 
    return m_value == ((Int32)obj).m_value; 
} 

Я посмотрел на Чару и Bool, и они оба делают тоже самое.

Источник: http://referencesource.microsoft.com/mscorlib/R/13ad4f778352f7c4.html

Это, однако, нарушает CA1800: Do not cast unnecessarily.

Кроме того, я провел несколько простых тестов с is и создал локальную переменную, и последнее, похоже, всегда дает лучшую производительность. Это как-то не относится к базовым типам? И, если нет, не правильно ли предположить, что, поскольку это базовый метод, его можно назвать миллионы раз в алгоритме, и, следовательно, производительность должна быть приоритетной?

+2

Как бы вы разыгрываете не-обнуляемым примитивный только один раз, не подвергаясь стоимости потенциального исключения? –

+0

Были ли ваши тесты с помощью 'struct' или' class'? – juharr

+0

@juharr. Тесты были с int, как и в примере, который я опубликовал. @ PatrykĆwiek прав, хотя я не помню, что кастинг с '(int)' может вызывать исключение. –

ответ

2

Предположим, вы просто бросили значение без оборонительного кода:

public override bool Equals(Object obj) 
{ 
    return m_value == ((Int32)obj).m_value; 
} 

С Equals может принять object, мы должны быть в состоянии не только пройти в int значений, но и, float, string, или практически любой тип. Хуже того, компилятор не будет жаловаться, потому что на самом деле все равно всего objects, так что звонок полностью легален.

Но что произойдет, если вы нанесете string на номер int? Мы получаем InvalidCastException во время выполнения, что совсем не приятно.

Таким образом, мы должны проверить, что object на самом деле int, перед заливкой его в int, это то, что ключевое слово is делает после того, как все.

Как примечание стороны, тело метода может также быть записано как:

return obj is Int32 ? m_value == ((Int32)obj).m_value : false; 
+1

Я не уверен, что ваша альтернативная реализация должна считаться * упрощением *. – CodesInChaos

+0

@CodesInChaos Вы правы, я изменил свое выражение –

+0

@MatiasCicero Да, вы совершенно правы, я не заметил этого, когда впервые посмотрел на исходный код. Спасибо за быстрый ответ, даже не могу его принять :) –

0

Оператор is используется для проверки типа obj.
Прямое приведение может привести к исключению, если obj не относится к тому типу, к которому вы его применили (Int32 в этом случае).
Чтобы предотвратить это потенциальное исключение, используется is.
Случаи, когда obj имеют другой тип, напрямую подпрыгивают при таком подходе.

+0

В противном случае вы можете сделать бросок в блоке try, если исключение поймано return false –

+0

Использование исключений для вещей, которые следует ожидать (и может быть обработано по-разному), неверно. Кроме того, в случае исключения производительность 'try ...catch' намного хуже, чем проверка 'is'. – Corak

+0

Я тоже согласен с этим, но я предложил альтернативу тем, кто не согласен. –

Смежные вопросы