隐式方法组转换问题

m0s*_*0sa 10 c# delegates

我想知道为什么给定代码的输出(在LinqPad中执行它)

void Main() {
    Compare1((Action)Main).Dump();
    Compare2(Main).Dump();
}

bool Compare1(Delegate x) {
    return x == (Action)Main;
}

bool Compare2(Action x) {
    return x == Main;
}
Run Code Online (Sandbox Code Playgroud)

总是:

 False
 True
Run Code Online (Sandbox Code Playgroud)

我天真地预计它会出现True在两种情况下.

Wik*_*hla 9

这是在编译为IL然后反编译回C#时的外观.请注意,在这两种情况下都有new Action(Main)- 一个新的引用对象(委托),其中包含指向存储在其中的实际方法的指针.

private static void Main()
{
    Program.Compare1(new Action(Program.Main)).Dump();
    Program.Compare2(new Action(Program.Main)).Dump();
    Console.ReadLine();
}

private static bool Compare1(Delegate x)
{
   return x == new Action(Program.Main);
}

private static bool Compare2(Action x)
{
   return x == new Action(Program.Main);
}
Run Code Online (Sandbox Code Playgroud)

如果那时我们看看CIL,前者使用ceq(参考比较),后者用于call bool [mscorlib]System.Delegate::op_Equality(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)比较代表.

首先返回,false因为包装代理的操作是两个不同的引用对象.

第二次返回,true因为在Delegate类上实现的相等运算符比较包装器(操作)中的实际目标.


Dmi*_*ryG 7

false结果是与该比较1()方法执行在两个不同的对象(compilator示出了相应的警告)基准比较的事实:

IL_0001:  ldarg.0
IL_0002:  ldnull
IL_0003:  ldftn      instance void ConsoleApplication1.Test::Main()
IL_0009:  newobj     instance void [System.Core]System.Action::.ctor(object,
                                                                   native int)
IL_000e:  ceq <<reference comparison
Run Code Online (Sandbox Code Playgroud)

您可以使用以下代码避免此问题:

bool Compare1(Delegate x) {
    return x == (Delegate)((Action)Main);
}
Run Code Online (Sandbox Code Playgroud)