Неявный метод группового преобразования Гоча - PullRequest
10 голосов
/ 20 января 2012

Мне интересно, почему вывод данного кода (выполнить его в 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 в обоих случаях.

Ответы [ 2 ]

9 голосов
/ 20 января 2012

Так выглядит при компиляции в 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) для сравнения делегатов.

Сначала возвращается false, потому что действия, обертывающие ваши делегаты, являются двумя различными ссылочными объектами.

Второй возвращает true, так как оператор равенства, реализованный в классе Delegate, сравнивает фактические цели внутри оболочек (действия).

7 голосов
/ 20 января 2012

Результат 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...