如何为响应式扩展制作自定义扩展

How to Make a Custom Extension for Reactive Extensions

不难找到how to make a custom LINQ extension method的例子。但是我找不到如何制作自定义 Rx 扩展方法的示例。

有人可以给我指点资源或 post 示例吗?我使用的是最新版本(2.2.5 版)。

我有兴趣定制 "Cast" 或定制 "Select"。我可以反映现有扩展的源代码,但仍然不明显。

谢谢。

在 Rx 中实现自定义扩展的最常见方法(除了组合现有操作)是通过 Observable.Create。强烈建议这样做,因为 Create 解决了很多问题,即自己实施并非易事。

无论您采用何种方式,请务必消化 the Rx Design Guidelines,其中解释了您应遵循的规则和惯例 - 其中许多 Observable.Create 会为您解决。

这是一个示例 Cast 实现:

public static class ObservableExtensions
{
    public static IObservable<TResult> Cast<TSource, TResult>(
        this IObservable<TSource> source)
    {
        return Observable.Create<TResult>(o =>
            source.Subscribe(x => {
                TResult cast;
                try
                {
                    cast = (TResult)(object)x;                        
                }
                catch (InvalidCastException ex)
                {
                    o.OnError(ex);
                    return;
                }
                o.OnNext(cast);
            },
            o.OnError,
            o.OnCompleted));
    }
}

我按原样说,因为双重演员要求并不明显(实际上 IEnumerableCast 出于同样的原因做同样的事情)。假设 object 转换是必要的,您可以进行此调整以将类型参数减少为一个:

public static class ObservableExtensions
{
    public static IObservable<TResult> Cast<TResult>(
        this IObservable<object> source)
    {
        return Observable.Create<TResult>(o =>
            source.Subscribe(x => {
                TResult cast;
                try
                {
                    cast = (TResult)x;
                }
                catch (InvalidCastException ex)
                {
                    o.OnError(ex);
                    return;
                }
                o.OnNext(cast);
            },
            o.OnError,
            o.OnCompleted));
    }       
}

您也可以在 IntroToRx 上查看有关 Observable.Create 的更多信息。

通常可以通过组合现有运算符来创建新的 Rx 运算符。例如,Cast 运算符可以在 built-in Select 运算符之上实现,如下所示:

public static IObservable<TResult> Cast<TSource, TResult>(
    this IObservable<TSource> source)
{
    return source.Select(x => (TResult)(object)x);
}