Упрощенный от этот вопрос и избавился от возможного влияния от LinqPad (без offsensive), простого консольного приложения вроде этого:
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();
}
}
"false" получается из оператора ceq
в CIL вышеприведенного кода (подробности см. в исходном вопросе). Поэтому мои вопросы:
(1) Почему ==
переводят на ceq
вместо call Delegate Equals
?
Здесь я не забочусь о (un) обертке между Delegate и Action. В самом последнем случае при оценке a == b
a имеет тип Action
, а b - Delegate
. Из спецификации:
7.3.4 Разрешение перегрузки двоичных операторов
Операция вида x op y, где op - перегружаемый двоичный оператор, x - выражение типа X, а y - выражение типа Y, обрабатывается следующим образом:
• Набор потенциальных пользовательских операторов, предоставляемых X и Y для операционный оператор op (x, y) определяется. Набор состоит из объединение кандидатов-операторов, предоставленных Х и кандидатом операторы, предоставленные Y, каждый определяется с использованием правил п. 7.3.5. Если X и Y являются одним и тем же типом, или если X и Y получены из общего базовый тип, то общие операторы-кандидаты встречаются только в комбинированном установить один раз.
• Если набор потенциальных пользовательских операторов не является пустой, то это становится набором операторов-кандидатов для операция. В противном случае предопределенный двоичный оператор op реализации, включая их поднятые формы, становятся кандидатов на операцию. Предопределенные реализации данного оператора указаны в описании оператора (§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.
• Для всех операторов op op в T0 и всех снятых формы таких операторов, если применим хотя бы один оператор (§7.5.3.1) относительно списка аргументов А, то множество оператор-кандидат состоит из всех таких применимых операторов в T0.
• В противном случае, если T0 является объектом, набор операторов-кандидатов пуст.
• В противном случае набор операторов-кандидатов, предоставляемых T0, является множеством операторов-кандидатов, предоставляемых прямым базовым классом T0, или эффективный базовый класс T0, если T0 является параметром типа.
Из спецификации a и b имеют один и тот же базовый класс Delegate
, очевидно, что здесь должно применяться правило оператора ==
, определенное в Delegate
(оператор == вызывает делегирование .Equals). Но теперь похоже, что список кандидатов определяемых пользователем операторов пуст и, наконец, применяется Object ==
.
(2) Должен (есть) код FCL подчиняться спецификации языка С#? Если нет, мой первый вопрос бессмыслен, потому что что-то специально рассматривается. И тогда мы можем ответить на все эти вопросы, используя "о, это особое обращение в FCL, они могут делать то, что мы не можем. Спектр предназначен для внешних программистов, не будь глупым".