Упрощено с этот вопрос и избавлено от возможного аффекта от LinqPad (без оскорблений), простого консольного приложения, подобного этому:
public class Program
{
static void M() { }
static void Main(string[] args)
{
Action a = new Action(M);
Delegate b = new Action(M);
Console.WriteLine(a == b); //got False here
Console.Read();
}
}
Оператор ceq
выдает «ложь» в приведенном выше коде (подробности см. В исходном вопросе). Итак, мои вопросы:
(1) Почему ==
переводится на ceq
вместо call Delegate Equals
?
Здесь меня не волнует (не) перенос между делегатом и действием. В самом последнем случае при оценке a == b
a имеет тип Action
, а b является Delegate
. Из спецификации:
7.3.4 Разрешение перегрузки бинарного оператора
Операция вида x op y, где op - это перегружаемый двоичный оператор, x - выражение
типа X, а y является выражением типа Y, обрабатывается следующим образом:
• Набор пользовательских операторов-кандидатов, предоставляемых X и Y для
оператор операции op (x, y) определен. Набор состоит из
объединение операторов-кандидатов, предоставляемых X и кандидатом
операторы, предоставляемые Y, каждый из которых определяется с использованием правил §7.3.5. Если
X и Y имеют одинаковый тип, или если X и Y получены из общего
базовый тип, то общие операторы-кандидаты встречаются только в сочетании
установить один раз.
• Если набор возможных пользовательских операторов не
пустым, то это становится набором операторов-кандидатов для
операция. В противном случае предопределенный бинарный оператор оп
реализации, включая их поднятые формы, становятся набором
операторы-кандидаты на операцию. Предопределенные реализации
данного оператора указаны в описании оператора
(§7.8–7.12).
• Правила разрешения перегрузки согласно §7.5.3
применяется к набору операторов-кандидатов для выбора лучшего оператора
относительно списка аргументов (x, y), и этот оператор становится
результат процесса разрешения перегрузки. Если разрешение перегрузки
не удается выбрать лучший оператор, возникает ошибка времени привязки.
7.3.5. Пользовательские операторы-кандидаты
Учитывая тип T и оператор операции op (A), где op - это перегружаемый оператор, а A - список аргументов, набор возможных пользовательских операторов, предоставляемых
T для оператора op (A) определяется следующим образом:
• Определить тип
T0. Если T является обнуляемым типом, T0 является его базовым типом, в противном случае T0
равно T.
• Для всех операторов операторов в T0 и всех снятых
формы таких операторов, если хотя бы один оператор применим
(§7.5.3.1) относительно списка аргументов A, то множество
операторы-кандидаты состоят из всех таких применимых операторов в T0.
• В противном случае, если T0 является объектом, набор операторов-кандидатов будет пустым.
• В противном случае набор операторов-кандидатов, предоставляемый T0, является набором
операторов-кандидатов, предоставляемых прямым базовым классом T0, или
эффективный базовый класс T0, если T0 является параметром типа.
Из спецификации, a и b имеют один и тот же базовый класс Delegate
, очевидно, здесь должно применяться правило оператора ==
, определенное в Delegate
(оператор == вызывает Delegate.Equals по существу). Но теперь похоже, что список кандидатов пользовательских операторов пуст и, наконец, применяется Object ==
.
(2) Должен ли код FCL подчиняться спецификации языка C #? Если нет, мой первый вопрос не имеет смысла, потому что что-то специально рассматривается. И тогда мы можем ответить на все эти вопросы, используя: «о, это особый подход в FCL, они могут делать то, что мы не можем. Спецификация для сторонних программистов, не будь глупой».