Как я могу получить IObservable <T> в Rx от “нестандартного” события?

Вот то, что я имею в виду. Предположим, что я работаю с API, который выставляет события, но эти события не следуют стандарту EventHandler или EventHandler<TEventArgs> подпись. Одно событие могло бы быть похожим на это, например:

Public Event Update(ByVal sender As BaseSubscription, ByVal e As BaseEvent)

Теперь, обычно, если я хочу добраться IObservable<TEventArgs> от события я могу просто сделать это:

Dim updates = Observable.FromEvent(Of UpdateEventArgs)( _
    target:=updateSource, _
    eventName:="Update" _
)

Но это не работает, потому что Update событие не EventHandler<UpdateEventArgs> - на самом деле, существует нет UpdateEventArgs - это - в основном просто своя собственная вещь.

Очевидно, я мог определить свой собственный класс, происходящий из EventArgs (т.е. UpdateEventArgs), запишите другой класс для обертывания объекта, обеспечивающего Update событие, дайте классу обертки его собственное Update событие, которое является EventHandler<UpdateEventArgs>, и доберитесь IObservable<UpdateEventArgs> от этого. Но это - раздражающий объем работы.

Есть ли некоторый способ создать IObservable<[something]> от "нестандартного" события как это, или я не повезло?


ОБНОВЛЕНИЕ: Из ответа Jon Skeet меня пошагово перемещают в направлении следующей перегрузки Observable.FromEvent:

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))

Я должен признать, тем не менее, что я испытываю затруднения при обертывании моей головы вокруг этого Func(Of EventHandler(Of TEventArgs), TDelegate) часть. Это кажется назад мне (?). Очевидно, существует только что-то, что я пропускаю...

Так или иначе, в случае, если это помогает, я думаю, что это - то, на что эквивалентный код C# был бы похож (я буду совершенно честен: я не уверен в этом. Даже при том, что я обычно предпочитаю C# сам, этот код является работой одного из моих коллег, который пишет, прежде всего, в VB.NET; и VB.NET разрешает несколько синтаксисов для объявления событий):

// notice: not an EventHandler<TEventArgs>
public delegate void UpdateEventHandler(BaseSubscription sender, BaseEvent e);

// not 100% sure why he did it this way
public event UpdateEventHandler Update;

Хитрая часть здесь - то, что кажется что некоторый класс, происходящий из EventArgs необходимо, несмотря ни на что. В API я работаю с, нет такого класса. Так, абсолютный минимум, я должен буду записать тот. Но это должно быть довольно тривиально (в основном одно свойство: BaseEvent).

В конце я предполагаю, что код, требуемый для этой перегрузки, выглядел бы примерно так в C#:

var updates = Observable.FromEvent<UpdateEventHandler, UpdateEventArgs>(
    // conversion (Func<EventHandler<UpdateEventArgs>, UpdateEventHandler>)
    handler => (sender, e) => handler(sender, new UpdateEventArgs(e)),
    // addHandler (Action<UpdateEventHandler>)
    handler => updateSource.Update += handler,
    // removeHandler (Action<UpdateEventHandler>)
    handler => updateSource.Update -= handler
);

В первую очередь: у меня даже есть это прямо? Второй из всех: я корректен в высказывании что использование VB 9, нет действительно никакого способа выполнить вышеупомянутое, не пишущий мои собственные методы?

Это почти чувствует мне как, я приближаюсь к этой проблеме от совершенно неправильного угла для начала. Но я действительно не уверен.

6
задан Enigmativity 19 October 2010 в 00:44
поделиться

3 ответа

Вы можете использовать эту подпись:

Public Shared 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))

Здесь TDelegate будет типом делегата события (что я могу ' Сразу видно из вашего объявления - объявления событий C # выглядят не совсем так, и, боюсь, я не знаю достаточно VB, чтобы расшифровать их, но я уверен, что где-то там есть тип делегата). TEventArgs будет типом для аргумента события (я думаю, BaseEvent должен сделать это здесь).Вам нужно будет предоставить преобразователь из EventHandler (Of BaseEvent) в ваш тип делегата - это, вероятно, будет просто лямбда-выражением для вызова данного обработчика событий с переданными в него аргументами. Действия добавления и удаления будут обычным кодом подписки на событие, но выражены в виде делегатов.

К сожалению, мой VB недостаточно хорош, чтобы выразить все это аккуратно - или действительно знать, сколько легко доступно в VB 9 или 10. Я знаю, как все это будет выглядеть на C # ... если бы вы могли дать мне короткий, но полный пример на C #, который просто оставил мне заполнить бит подписки, я определенно мог бы это сделать ...

1
ответ дан 17 December 2019 в 02:24
поделиться

Возможно, вы могли бы просто добавить свою собственную реализацию для настраиваемой сигнатуры события?

public interface ICustomEvent<TSource, TArgs>
{
    public TSource Source { get; }
    public TArgs EventArgs { get; }
}

public interface CustomEvent<TSource, TArgs> : ICustomEvent<TSource, TArgs>
{
    public TSource Source { get; set; }
    public TArgs EventArgs { get; set; }
}

public static class ObservableEx
{
    public static IObservable<ICustomEvent<TSource, TArgs>> FromCustomEvent(
        Action<Action<TSource, TArgs>> addHandler, 
        Action<Action<TSource, TArgs>> removeHandler)
    {
        return Observable.CreateWithDisposable(observer =>
            {
                Action<TSource, TArgs> eventHandler = (s,a) => 
                    observer.OnNext(new CustomEvent<TSource,TArgs>(s,a));

                addHandler(eventHandler);

                return Disposable.Create(() => removeHandler(eventHandler));
            });
    }
}

Тогда вы можете использовать ее как:

var observable = ObservableEx.FromCustomEvent<BaseSubscription,BaseEvent>(
    h => updateSource.Update += h,
    h => updateSource.Update -= h
);
3
ответ дан 17 December 2019 в 02:24
поделиться

Вы также можете просто сделать это ленивым способом, если updateSource никогда не исчезнет:

var observable = new Subject<BaseEvent>();
updateSource.Update += (o,e) => observable.OnNext(e);

План Джона, вероятно, лучше, но Субъекты могут вам помочь.

1
ответ дан 17 December 2019 в 02:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: