反应性扩展,包装第三方API事件 - 零拷贝?

Iva*_*van 0 c# system.reactive zero-copy

我有第三方API,我没有源代码.我实例化一个回调到这样的事件:

using namespace API; // This is where APIClient lives

namespace TestApiClientUI
{
    public partial class Form1 : Form
    {
        APIClient apiClient = new APICLient();
        apiClient.QuoteUpdated += api_ClientUpdated;

        private void api_ClientUpdated(object sender, string s, double b, double a)
        {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如何将其包装到Rx Observable.FromEvent中?

另外,有没有办法做到这一点所以包装副本的开销尽可能少(零拷贝)?

Tim*_*lds 7

让我们定义一个结构来存储事件args.

struct QuoteUpdate
{
    public string S { get; private set; }
    public double B { get; private set; }
    public double A { get; private set; }
    public QuoteUpdate(string s, double b, double a) : this()
    {
        S = s;
        B = b;
        A = a;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以定义IObservable<QuoteUpdate>如下.

var quoteUpdates = Observable.FromEvent<ApiQuoteHandler, QuoteUpdate>(
    emit => (_, s, b, a) => emit(new QuoteUpdate(s, b, a)),
    handler => apiClient.QuoteUpdated += handler,
    handler => apiClient.QuoteUpdated -= handler);
Run Code Online (Sandbox Code Playgroud)

第一个lambda定义了从Action<QuoteUpdate>到的映射ApiQuoteHandler.被称为的动作emit实际上是向我们定义的可观察对象的订阅者广播一个值.想象emit(value);一下这样的事情foreach (var subscriber in subscribers) { subscriber.OnNext(value); }.

我们需要第一个映射的原因是因为实际的底层事件只知道如何订阅和取消订阅ApiQuoteHandler实例.第二和第三个lambda属于类型Action<ApiQuoteHandler.它们分别被称为订阅和取消订阅.

IObserver<QuoteUpdate> observer订阅IObservable<QuoteUpdate>我们已定义的时,会发生以下情况:

  1. observer.OnNext(类型Action<QuoteUpdate>)作为变量传递给我们的第一个lambda emit.这创造了一个ApiQuoteHandler包装observer.
  2. ApiQuoteHandler随后被传递到我们的第二拉姆达为变量handler.该handler订阅到QuoteUpdated你的事件apiClient.
  3. 我们IDisposable返回的from Subscribe方法IObservable<QuoteUpdate>包含ApiQuoteHandler对我们三个lambdas中第一个创建的引用.
  4. 当稍后IDisposable处理时,第三个lambda被调用与ApiQuoteHandler之前相同的,取消订阅基础事件.

因为你需要一个单独IObservable<T>T事件而你有事件参数(s, b, a),你必须定义一些结构或类来存储这三个值.我不担心复制string引用和两个double值的成本.