C# 在Rx中可观察到回调

C# 在Rx中可观察到回调,c#,callback,system.reactive,observable,C#,Callback,System.reactive,Observable,我正在寻找一种优雅的方法,从带有Rx的普通回调委托创建一个可观察的,类似于 比如说,我正在包装Win32 API,它将调用我提供的EnumWindowsProc 我知道我可以为这个回调创建一个临时C#事件适配器,并从EventPattern中传递它。此外,我可能可以手动实现IObservable,因此它将从我的EnumWindowsProc回调调用IObserver.OnNext 在Rx中是否存在我所缺少的包装回调的现有模式?您可以使用,它可以用于从命令式编程世界进入Rx的功能世界 Subjec

我正在寻找一种优雅的方法,从带有Rx的普通回调委托创建一个可观察的
,类似于

比如说,我正在包装Win32 API,它将调用我提供的
EnumWindowsProc

我知道我可以为这个回调创建一个临时C#事件适配器,并从EventPattern中传递它。此外,我可能可以手动实现
IObservable
,因此它将从我的
EnumWindowsProc
回调调用
IObserver.OnNext

在Rx中是否存在我所缺少的包装回调的现有模式?

您可以使用,它可以用于从命令式编程世界进入Rx的功能世界

Subject
实现了
IObservable
IObserver
,因此您可以调用其
OnNext
OnError
OnCompleted
方法,并将通知订阅者


如果要将
主题
作为属性公开,则应使用
.AsObservable()
进行公开,因为这隐藏了
ioobservable
实际上是
主题的事实。它使诸如
((Subject)obj.Event).OnNext(“Foo”)
之类的事情变得不可能。

请记住,类似于
枚举窗口中使用的回调与Rx中的回调有细微的不同。具体来说,回调可以通过其返回值与调用者通信。Rx观察员无法做到这一点。此外,回调可以接收多个参数,但Rx观察器只接收一个值。因此,您需要将多个参数包装到单个对象中

考虑到这一点,使用
主题
的另一种选择是使用
可观察。创建
。这样,只有在实际有观察者时才注册回调,如果该观察者取消订阅,则取消注册回调

对于您使用的同步API示例,您可以执行以下操作。注意,在这个示例中,实际上没有一种方法可以取消注册回调中流,因为在返回unsubscribe命令之前,所有回调都是同步进行的

public static IObservable<Foo> WrapFooApi(string arg1, string arg2)
{
    return Observable.Create<Foo>(observer =>
    {
        FooApi.enumerate(arg1, arg2, e =>
        {
            observer.OnNext(new Foo(e));
            return true;
        });

        // In your case, FooApi.enumerate is actually synchronous
        // so when we get to this line of code, we know
        // the stream is complete.
        observer.OnCompleted();
        return Disposable.Empty;
    });
}

// Usage
WrapFooApi("a", "b").Take(1).Subscribe(...); // only takes first item
在更传统的异步回调API中,您可以在某个点注册,在另一个点取消注册,您可能会遇到以下情况:

public static IObservable<Foo> WrapFooApi(string args)
{
    return Observable.Create<Foo>(observer =>
    {
        FooToken token = default(FooToken);
        var unsubscribe = Disposable.Create(() => FooApi.Unregister(token));
        token = FooApi.Register(args, e =>
        {
            observer.OnNext(new Foo(e));
        });

        return unsubscribe;
    });
}
publicstaticiobservable-WrapFooApi(字符串参数)
{
返回可观察的。创建(观察者=>
{
FooToken令牌=默认值(FooToken);
var unsubscribe=Disposable.Create(()=>FooApi.Unregister(令牌));
token=FooApi.Register(args,e=>
{
OnNext观察员(新Foo(e));
});
退订;
});
}

或者您可以简单地使用
主题
并在回调中调用
OnNext
。@Dirk,很有趣,谢谢。因此,
Subject.OnNext
然后
Subject.OnComplete
当没有更多项目时?是的,Subject实现了
IObservable
IObserver
。调用OnNext/OnError/OnCompleted向主题的订阅者发出这些命令。他们服务器就像一个从非接收代码到接收代码的网关。@Dirk,谢谢,也许你应该把它作为一个答案发布。这可能是正确的选择。在接受它之前,我只想看看别人会说些什么。@avo这当然是一个简单的解决方案,但有些人不喜欢使用主题,因为这是Rx中为数不多的非功能性内容之一。我认为它有一些很好的用途,但是如果有其他方法,比如FromEventPattern,那么我会使用它。我不认为在这种特殊情况下,您可以使用任何异步API来实现这一点-EnumWindows回调是从调用方同步调用的(即,假设EnumWindows API只使用for循环并为每个项调用回调)
public static IObservable<Foo> WrapFooApi(string args)
{
    return Observable.Create<Foo>(observer =>
    {
        FooToken token = default(FooToken);
        var unsubscribe = Disposable.Create(() => FooApi.Unregister(token));
        token = FooApi.Register(args, e =>
        {
            observer.OnNext(new Foo(e));
        });

        return unsubscribe;
    });
}