Каковы аргументы в пользу отказа оператора Object ==, когда один операнд является интерфейсом?

Рассмотрим следующие типы:

class A { }
class B { }
interface IC { }

A a = null; // the value doesn't matter - null or anything else, for all three
B b = null;
IC c = null;

Следующий делает не компиляцию:

var x = a == b;

Но следующий делает компиляцию (как я с удивлением обнаружил):

var x = a == c;

Как я понимаю, компилятор возвращается к использованию оператора по умолчанию ==, который определен на объекте и таким образом принимает любой тип для своих аргументов. IL выглядит так (игнорируйте детали ldfld):

ldarg.0
ldfld class A a
ldarg.0
ldfld class IC c
ceq
stloc.0

Другими словами, он использует ссылочное равенство.

Мои вопросы:

  • Что касается дизайна языка, почему это имеет смысл? Для меня это не так, и я считаю это большой ловушкой.

  • Если это действительно ошибка, не следует ли нам анализировать Code Analysis? (нет - это не так). Кстати, У ReSharper есть эта функция.

Ответ 1

Причина, по которой компиляция второй строки заключается в том, что может быть другой класс, который происходит от A и реализует IC.

public class D : A, IC {}
...
a = new D(); c = a; var t = a == c; //t = true;

Классы могут наследовать только один класс, поэтому вы никогда не сможете создать класс, который наследует от A и B, если A не является потомком B или наоборот.

Ответ 2

Причина, по которой тест a == b не компилируется, заключается в том, что у компилятора достаточно информации, чтобы знать, что тест не может быть когда-либо true, поскольку два класса не находятся в одной иерархии. Поэтому это эквивалент компилятора, который не позволяет вам написать условие, которое на самом деле является константой по ошибке.

Для сравнения интерфейсов компилятор видит, что существует operator==(object, object), который он может использовать, и поскольку оба A и IC неявно конвертируются в object, то, что на самом деле должно произойти. Очень может быть другой тип (даже не обязательно ссылочный тип), который реализует IC, поэтому условие является подлинным.

Предупреждение R # - это то, что я ценю; как видно на странице, сравнение сравнений между типами интерфейсов в некоторых случаях несколько сомнительно и там чрезвычайно описательно, просто заменить на решение: object.ReferenceEquals. Конечно, есть контр-аргумент, что оператор равенства мог быть перегружен, поэтому тест может быть значимым. Или это просто может быть кто-то писать в более краткий стиль. Очевидно, что запрещение такого использования в компиляторе несколько тяжело.