【发布时间】:2012-02-14 21:31:33
【问题描述】:
从this question 简化并摆脱了 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();
}
}
上述代码的 CIL 中的运算符 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 派生自一个共同的 基本类型,则共享候选运算符仅出现在组合中 设置一次。
• 如果候选用户定义运算符集不是 为空,则这成为候选运算符的集合 手术。否则,预定义的二元运算符 op 实现,包括它们的提升形式,成为一组 操作的候选运算符。预定义的实现 给定运算符的描述在运算符的描述中指定 (§7.8 至 §7.12)。
• §7.5.3 的重载解决规则是 应用于候选算子集合以选择最佳算子 关于参数列表 (x, y),这个运算符变成 重载解决过程的结果。如果重载决议 未能选择单个最佳运算符,发生绑定时错误。
7.3.5 候选用户定义运算符
给定一个类型 T 和一个操作运算符 op(A),其中 op 是一个可重载的运算符,A 是一个参数列表,候选用户定义运算符的集合由 运算符 op(A) 的 T 确定如下:
• 确定类型 T0。如果 T 是可空类型,则 T0 是其基础类型,否则 T0 等于T。
• 对于 T0 中的所有运算符 op 声明并全部解除 此类运算符的形式,如果至少有一个运算符适用 (§7.5.3.1)关于参数列表A,那么集合 候选算子由T0中所有适用的算子组成。
• 否则,如果 T0 为对象,则候选运算符集为空。
• 否则,T0 提供的候选算子集合就是集合 由 T0 的直接基类或 如果 T0 是类型参数,则 T0 的有效基类。
从规范来看,a 和 b 具有相同的基类Delegate,显然这里应该应用Delegate 中定义的运算符规则==(运算符== 本质上调用Delegate.Equals)。但现在看起来用户自定义运算符的候选列表为空,最后应用了Object ==。
(2) FCL 代码应该(是否)遵守 C# 语言规范?如果不是,我的第一个问题是没有意义的,因为有些东西是经过特殊处理的。然后我们可以用“哦,这是 FCL 中的特殊处理,他们可以做我们做不到的事情。规范是针对外部程序员的,别傻了”来回答所有这些问题。
【问题讨论】:
-
这就是为什么在期望值类型语义时最好使用
Equals。因为(可能)损坏的运算符重载。 -
@Groo:没错。顺便说一句,我收到了问题
Possible unintended reference comparison; to get a value comparison, cast the right hand side to type 'System.Action'中代码的编译警告。 -
这肯定与一般委托的特殊处理有关,因为使用用户定义的类层次结构尝试相同的事情会调用自定义
==方法
标签: c# .net operator-overloading