【问题标题】:Implicit method group conversion gotcha隐式方法组转换陷阱
【发布时间】:2012-01-20 08:16:35
【问题描述】:

我想知道为什么给定代码的输出(在 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;
}

总是:

 False
 True

我天真地期望在这两种情况下都是True

【问题讨论】:

  • Compare1 更改为使用return x == (Delegate)(Action)Main; 使其返回true。不知道为什么。
  • 仅供参考:我在这里问了一个相关问题:stackoverflow.com/questions/8939350/…

标签: c# delegates


【解决方案1】:

这是编译成 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);
}

如果然后我们看一下 CIL,前者使用ceq(参考比较),后者使用call bool [mscorlib]System.Delegate::op_Equality(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate) 来比较委托。

First 返回 false,因为包装您的委托的操作是两个不同的引用对象。

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

【讨论】:

    【解决方案2】:

    false结果与Compare1()方法对两个不同对象进行引用比较有关(编译器显示相应的警告):

    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
    

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

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

    【讨论】:

      猜你喜欢
      • 2012-02-14
      • 2012-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多