C # делегат под капотом
-
03-10-2019 - |
Вопрос
Я делал какую-то копание в делегатную дисперсию после прочтения следующего вопроса в так: Delage.createdelegate () и дженерики: привязка ошибок к целевому методу
Я нашел очень хороший код из Барри Келли вhttps://www.blogger.com/comment.gblogid=8184237816669520763669520763&postid=2109708553230166434.
Вот оно (в форме сахара :-)
using System;
namespace ConsoleApplication4
{
internal class Base
{
}
internal class Derived : Base
{
}
internal delegate void baseClassDelegate(Base b);
internal delegate void derivedClassDelegate(Derived d);
internal class App
{
private static void Foo1(Base b)
{
Console.WriteLine("Foo 1");
}
private static void Foo2(Derived b)
{
Console.WriteLine("Foo 2");
}
private static T CastDelegate<T>(Delegate src)
where T : class
{
return (T) (object) Delegate.CreateDelegate(
typeof (T),
src.Target,
src.Method,
true); // throw on fail
}
private static void Main()
{
baseClassDelegate a = Foo1; // works fine
derivedClassDelegate b = Foo2; // works fine
b = a.Invoke; // the easy way to assign delegate using variance, adds layer of indirection though
b(new Derived());
b = CastDelegate<derivedClassDelegate>(a); // the hard way, avoids indirection
b(new Derived());
}
}
}
Я понимаю все это, кроме этого (что выглядит очень простой) линию.
B = A.invoke; // Простой способ назначить делегата с использованием дисперсии, добавляет слой косвествия, хотя
Кто-нибудь может сказать мне:
- Как можно позвонить, не передавая параметра, требуемый статической функцией.
- Когда происходит под капотом, когда вы назначаете возвращаемое значение от вызывающего вызова
- Что такое Барри подразумевает дополнительное косвествие (в его комментарии)
Решение
Он не звонит Invoke
(Обратите внимание на отсутствие ()
), он использует неявное создание делегата для установки b
равный новой derivedClassDelegate
экземпляр, который указывает на Invoke
метод a
. Отказ Дополнительное косвенное управление это то, когда b
вызывается, это называет a.Invoke(new Derived())
а не просто a(new Derived())
.
Сделать то, что на самом деле происходит более явным:
baseClassDelegate a = Foo1; // works fine
derivedClassDelegate b = Foo2; // works fine
b = new derivedClassDelegate(a.Invoke); // the easy way to assign delegate using variance, adds layer of indirection though
b(new Derived());
b = CastDelegate<derivedClassDelegate>(a); // the hard way, avoids indirection
b(new Derived());
Первый звонок к b
Результаты в цепочке, как это (параметры, удаленные для простоты):
b() -> a.Invoke() -> Foo1()
Второй звонок к b
Результаты в этом:
b() -> Foo1()
Однако
Это только необходимо, если вам нужен делегат одной подписи, чтобы вызвать делегат другой (менее ограничительной) подписи. В его примере вы могли бы просто установить b = Foo1
И это будет компилировать, но это не проиллюстрирует точку.