У меня похожий кошмар, потому что я работаю с API взаимодействия, использующим нестандартные события .net. Я новичок во многих вещах, включая Generics, Funcs, Actions, Observables и Rx, поэтому я считаю, что мой опыт понимания таких вещей будет иметь определенную ценность.
Мы можем разобраться с Func(Of EventHandler(Of TEventArgs), TDelegate) conversion
, поняв, где оно используется.
Но сначала мы должны понять обобщенную сигнатуру FromEvent
метода.
Ниже приведена сигнатура функции метода расширения FromEvent в vb:
Function FromEvent(Of TDelegate, TEventArgs As EventArgs)( _
conversion As Func(Of EventHandler(Of TEventArgs), TDelegate), _
addHandler As Action(Of TDelegate), _
removeHandler As Action(Of TDelegate) _
) As IObservable(Of IEvent(Of TEventArgs))
Но я на самом деле не использую vb, поэтому мне придется прибегнуть к подписи c #:
IObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>(
Func<Action<TEventArgs>, TDelegate> conversion,
Action<TDelegate> addHandler,
Action<TDelegate> removeHandler);
Давайте разберем подпись c # построчно.
Примечание. Будут случаи, когда я буду включать типы данных в лямбда-выражения, чтобы отличать стандартные события .net от нестандартных событий.
Первая часть:
IObservable<TEventArgs> FromEvent<TDelegate, TEventArgs>(
Это говорит о том, что функция FromEvent принимает TDelegate
и TEventArgs As EventArgs
в качестве ВХОДА. Обратите внимание, что OUTPUT IObservable
также будет иметь тип TEventArgs
Так что вы правы, когда сказали, что вам нужен класс, который обернет данные TDelegate
. Я не знаю, какую версию я использую, но она позволяет мне использовать любой класс, даже если он не наследуется от EventArgs
. В случае, если vb не позволяет вам, это все равно тривиальная работа, так как он просто добавляет :EventArgs
к классу (Наследует от vb?). Давайте применим это к вашей проблеме:
Ваши предположения c #:
// notice: not an EventHandler<TEventArgs> public delegate void
public delegate void UpdateEventHandler(BaseSubscription sender, BaseEvent e);
// class to wrap the data from the above delegate
public class UpdateEventArgs:EventArgs {...}
Применение к первой строке становится:
var updates = FromEvent<UpdateEventHandler, UpdateEventArgs>(
Вторая часть:
Далее у нас есть три входа conversion
, addhandler
и removehandler
:
Func<Action<TEventArgs>, TDelegate> conversion,
Action<TDelegate> addHandler,
Action<TDelegate> removeHandler);
Мы знаем, что addHandler
и removeHandler
просто добавляют и удаляют делегата из события. Давайте сначала сделаем эти два.
// addHandler (Action<UpdateEventHandler>)
handler => updateSource.Update += handler,
// removeHandler (Action<UpdateEventHandler>)
handler => updateSource.Update -= handler
Теперь давайте применим наш тип к сложной части:
Func<Action<UpdateEventArgs>, UpdateEventHandler> conversion,
Эта функция принимает Action<UpdateEventArgs>
в качестве ввода, а UpdateEventHandler
делегат - в качестве выхода. Давайте назначим его в переменной с именем conversion
Func<Action<UpdateEventArgs>, UpdateEventHandler> conversion
= (handlerOfUpdateEventArgs) =>
{
UpdateEventHandler handler = (BaseSubscription sender, BaseEvent e) =>
handlerOfUpdateEventArgs(sender, new UpdateEventArgs(e));
return handler;
};
Чтобы лучше понять, что это делает, давайте посмотрим, как мы прикрепляем обработчик событий к стандартному событию .net:
someObject.SomeEvent += (object sender,EventArgs args) => { ... };
Теперь мы смотрим на ваше нестандартное событие .net и UpdateEventHandler
:
public delegate void UpdateEventHandler(BaseSubscription sender, BaseEvent e);
updateSource.Update += (BaseSubscription sender, BaseEvent e) => { ... };
Если вы посмотрите на сигнатуру функции conversion
, она вернет делегат UpdateEventHandler
. Это будет означать, что мы можем использовать conversion
, чтобы присоединиться к событию Update
. Но прежде чем мы сможем это сделать, функции conversion
необходимо ввести Action<UpdateEventArgs>
, прежде чем ее можно будет использовать. Давайте сделаем это сейчас:
//EventHandler<EventArgs> similarity.
Action<UpdateEventArgs> actionUpdateEventArgs = (UpdateEventArgs e) =>
{
//This is were you put your code like in a standard.net event
//This is also probably where the Observable.FromEvent() puts
//wiring necessary to make it into an IObservable<UpdateEventArgs>
};
Теперь, когда у нас есть все необходимые нам части, мы можем использовать conversion
аналогично обработчику событий.
updateSource.Update += conversion(actionUpdateEventArgs);
Код в actionUpdateEventArgs
будет вызываться каждый раз, когда Update
повышается.
Надеюсь, этого было достаточно для понимания параметра Func<Action<UpdateEventArgs>, UpdateEventHandler> conversion
.
Наконец, вот как вы будете использовать метод FromEvent()
:
Func<Action<UpdateEventArgs>, UpdateEventHandler> conversion
= (handlerOfUpdateEventArgs) =>
{
UpdateEventHandler handler = (BaseSubscription sender, BaseEvent e) =>
handlerOfUpdateEventArgs(sender, new UpdateEventArgs(e));
return handler;
};
var updates = Observable.FromEvent<UpdateEventHandler, UpdateEventArgs>(
// conversion (Func<EventHandler<UpdateEventArgs>, UpdateEventHandler>)
conversion,
// addHandler (Action<UpdateEventHandler>)
handler => updateSource.Update += handler,
// removeHandler (Action<UpdateEventHandler>)
handler => updateSource.Update -= handler
);
Вот как я понял это с точки зрения новичков, поэтому я надеюсь, что это будет полезно.