从这个问题简化并摆脱了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();
}
}
Run Code Online (Sandbox Code Playgroud)
操作员ceq在上述代码的CIL中产生"错误" (有关详细信息,请访问原始问题).所以我的问题是:
(1)为什么==要翻译ceq而不是call Delegate Equals?
在这里,我不关心Delegate和Action之间的(un)包装.最后,在评估时a == b,a是类型,Action而b是a Delegate.从规格:
7.3.4二元运算符重载决策
形式为x op y的操作,其中op是可重载的二元运算符,x是类型X的表达式,y是类型Y的表达式,按如下方式处理:
•确定由操作运算符op(x,y)的X和Y提供的候选用户定义运算符集.该集合由X提供的候选运算符和Y提供的候选运算符组合而成,每个运算符使用§7.3.5的规则确定.如果X和Y是相同类型,或者如果X和Y是从公共基类型派生的,则共享候选运算符仅出现在组合集中一次.
•如果候选用户定义的运算符集不为空,则此变为该操作的候选运算符集.否则,预定义的二元运算符op实现(包括它们的提升形式)将成为该操作的候选运算符集.给定运算符的预定义实现在运算符的描述中指定(第7.7节到第7.12节).
•§7.5.3的重载决策规则应用于候选运算符集合,以选择与参数列表(x,y)相关的最佳运算符,并且此运算符成为重载解析过程的结果.如果重载决策未能选择单个最佳运算符,则会发生绑定时错误.
7.3.5候选用户定义的运算符
给定类型T和操作运算符op(A),其中op是可重载运算符,A是参数列表,由T为运算符op(A)提供的候选用户定义运算符集合如下确定:
•确定类型T0.如果T是可空类型,则T0是其基础类型,否则T0等于T.
•对于T0中的所有运算符op声明和此类运算符的所有提升形式,如果关于参数列表A至少有一个运算符适用(第7.5.3.1节),则候选运算符集包含所有此类适用运算符. T0.
•否则,如果T0是对象,则候选运算符集为空.
•否则,T0提供的候选运算符集合是由T0的直接基类提供的候选运算符集合,或者如果T0是类型参数则是T0的有效基类.
从规范中,a和b具有相同的基类Delegate,显然应该在这里应用==定义的运算符规则Delegate(operator ==从本质上调用Delegate.Equals).但现在看起来用户定义的运算符的候选列表是空的,最后 …