Ответ 1
Позвольте сломать его:
Во-первых, декомпиляция Rx v2.0.3, по-видимому, не имеет метода Observable.FromEvent<TEventHandler, TEventHandlerArgs>(add, remove)
, и также не существует Rx v 1.1, с которым я столкнулся. Я собираюсь предположить, что вы имеете в виду ближайшее совпадение, которое я могу найти:
public static IObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>(Action<TDelegate> addHandler, Action<TDelegate> removeHandler)
Глядя на декомпилированный источник для Rx 1.1 (источник 2.0 отправился на нас всем астронавтом архитектуры и полон косвенности, что делает его намного сложнее). Фактический фрагмент кода, использующий рефлектор для декомпиляции, таков:
Action<TEventArgs> o = new Action<TEventArgs>(observer.OnNext);
TDelegate d = CreateDelegate<TDelegate>(o,
typeof(Action<TEventArgs>).GetMethod("Invoke"));
addHandler(d);
Итак, вопрос:
Как создается CreateDelegate делегат подписи (obj, args), связанный с методом invoke (args) для действия? Где находится объект?
Я не уверен, понял ли я совершенно правильно, но, похоже, вопрос конкретно имеет значение. Как CreateDelegate<TDelegate>(o, typeof(Action<TEventArgs>).GetMethod("Invoke")
создает метод только с параметром args
- что происходит с объектом o
Что происходит, да, объект o
передается как object firstArgument
для внутреннего .NET-метода.
public static Delegate CreateDelegate(Type type, object firstArgument, MethodInfo method, bool throwOnBindFailure)
Этот метод "связывает" firstArgument в основном как указатель this
для возвращаемого метода. Внутри он будет хранить ссылку на firstArgument где-то внутри объекта делегата. Мы не можем видеть внутри этого, поскольку это внутренняя деталь реализации .NET и поэтому она может делать всевозможные нечетные вещи и нарушать правила там, где это угодно.
Похоже, что это может быть вокруг открытого делегата по действию, и мы принуждаем 'this' быть "firstArguemnt" из CreateDelegate и разрешать прохождение args. Если так кажется грязным?
Да, это точно то, что происходит. Это то, что предназначена для функции CreateDelegate
.
Кроме того, он становится еще более грязным. CreateDelegate
просто возвращает объект типа Delegate
- у нас нет безопасности типа в методах args и т.д., а затем код переводит его в TDelegate
- это работает, потому что делегат является особым, и вы можете отнести его на любой который имеет ту же "форму". Как и выше, это внутренняя деталь реализации .NET и поэтому может выполнять всевозможные странные вещи: -)