c# - 如何封装可观察到的长 react 链的创建

标签 c# system.reactive fluent reactiveui

目前我有以下 Rx/ReactiveUI 代码块:

        this.WhenAnyValue(x => x.Listras)
            .Where(item => item != null)
            .Throttle(TimeSpan.FromMilliseconds(millis))
            .ObserveOn(TaskPoolScheduler.Default)
            .Select(im => GetArray.FromChannels(im, 0, 1))
            .ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.Grayscale, out _grayscale);

        this.WhenAnyValue(x => x.Grayscale)
            .Where(item => item != null)
            .Throttle(TimeSpan.FromMilliseconds(millis))
            .ObserveOn(TaskPoolScheduler.Default)
            .Select(ar => Gaussian.GaussianConvolution(ar, 1.5))
            .ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.BlurMenor, out _blurMenor);

        this.WhenAnyValue(x => x.BlurMenor)
            .Where(item => item != null)
            .Throttle(TimeSpan.FromMilliseconds(millis))
            .ObserveOn(TaskPoolScheduler.Default)
            .Select(ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; })
            .ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.ImagemBlurMenor, out _imagemBlurMenor);

        this.WhenAnyValue(x => x.BlurMenor)
            .Where(item => item != null)
            .Throttle(TimeSpan.FromMilliseconds(millis))
            .ObserveOn(TaskPoolScheduler.Default)
            .Select(ar => Gaussian.VerticalGaussianConvolution(ar, 5))
            .ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.BlurMaior, out _blurMaior);

        this.WhenAnyValue(x => x.BlurMaior)
            .Where(item => item != null)
            .Throttle(TimeSpan.FromMilliseconds(millis))
            .ObserveOn(TaskPoolScheduler.Default)
            .Select(ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; })
            .ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.ImagemBlurMaior, out _imagemBlurMaior);

        this.WhenAnyValue(x => x.BlurMenor, x => x.BlurMaior)
            .Where(tuple => tuple.Item1 != null && tuple.Item2 != null)
            .Throttle(TimeSpan.FromMilliseconds(millis))
            .ObserveOn(TaskPoolScheduler.Default)
            .Select(tuple => ArrayOperations.Diferença(tuple.Item1, tuple.Item2))
            .ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.Diferença, out _diferença);

        this.WhenAnyValue(x => x.Diferença)
            .Where(item => item != null)
            .Throttle(TimeSpan.FromMilliseconds(millis))
            .ObserveOn(TaskPoolScheduler.Default)
            .Select(ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; })
            .ObserveOn(RxApp.MainThreadScheduler)
            .ToProperty(this, x => x.ImagemDiferença, out _imagemDiferença);

如您所见,它公然违反了 DRY 原则,但我不知道如何将属性和委托(delegate)的传递参数化。

在 Rx/ReactiveUI 中自动创建这些方法链的常用方法是什么?

最佳答案

Rx 的美妙之处在于您可以基于其他运算符创建自己的运算符。这是因为 Rx 的功能方面。

您可以创建一个新的运算符,它封装了所有常见的行为并将细小的差异作为参数:

// Put this class somewhere useful. Either beside your VM inside the same namespace
// Or in a seperate file for all your custom operators
public static class ObservableMixins
{
    public static IObservable<TOut> ThrottledSelect<TIn, TOut>(this IObservable<TIn> source, int milliseconds, Func<TIn, TOut> selector) =>
        source
            .Where(item => item != null)
            .Throttle(TimeSpan.FromMilliseconds(milliseconds))
            .ObserveOn(TaskPoolScheduler.Default)
            .Select(selector)
            .ObserveOn(RxApp.MainThreadScheduler)
}

像这样使用它:

this.WhenAnyValue(x => x.Listras)
    .ThrottledSelect(millis, im => GetArray.FromChannels(im, 0, 1))
    .ToProperty(this, x => x.Grayscale, out _grayscale);

this.WhenAnyValue(x => x.Grayscale)
    .ThrottledSelect(millis, ar => Gaussian.GaussianConvolution(ar, 1.5))
    .ToProperty(this, x => x.BlurMenor, out _blurMenor);

this.WhenAnyValue(x => x.BlurMenor)
    .ThrottledSelect(millis, ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; })
    .ToProperty(this, x => x.ImagemBlurMenor, out _imagemBlurMenor);

this.WhenAnyValue(x => x.BlurMenor)
    .ThrottledSelect(millis, ar => Gaussian.VerticalGaussianConvolution(ar, 5))
    .ToProperty(this, x => x.BlurMaior, out _blurMaior);

this.WhenAnyValue(x => x.BlurMaior)
    .ThrottledSelect(millis, ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; })
    .ToProperty(this, x => x.ImagemBlurMaior, out _imagemBlurMaior);

this.WhenAnyValue(x => x.BlurMenor, x => x.BlurMaior)
    // Notice how I'm returning a null if either item is null
    // It will be filtered in the operator
    .Select(tuple => tuple.Item1 != null || tuple.Item2 != null ? null : tuple)
    .ThrottledSelect(millis, tuple => ArrayOperations.Diferença(tuple.Item1, tuple.Item2))
    .ToProperty(this, x => x.Diferença, out _diferença);

this.WhenAnyValue(x => x.Diferença)
    .ThrottledSelect(millis, ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; })
    .ToProperty(this, x => x.ImagemDiferença, out _imagemDiferença);

如果您不那么喜欢冒险,您当然可以将其用作采用可观察对象的常规方法:

public IObservable<T> ThrottledSelect<TIn, TOut>(IObservable<TIn> source, int milliseconds, Func<TIn, TOut> selector) =>
    source
        .Where(item => item != null)
        .Throttle(TimeSpan.FromMilliseconds(milliseconds))
        .ObserveOn(TaskPoolScheduler.Default)
        .Select(selector)
        .ObserveOn(RxApp.MainThreadScheduler)

然后像这样使用它:

ThrottledSelect(this.WhenAnyValue(x => x.Diferença), millis, ar => { ConversorImagem.Converter(ar, out BitmapSource im); return im; })
    .ToProperty(this, x => x.ImagemDiferença, out _imagemDiferença);

关于c# - 如何封装可观察到的长 react 链的创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45147895/

相关文章:

c# - 创建一个你可以在 RxCpp 中取消订阅的 Observable

c# - 订户丢失消息;这是 Rx 的错误还是我做错了?

c# - 将 C# DLL 合并到 .EXE

fluent - 有流畅的接口(interface)吗?

php - 使用 Laravel Fluent 如何更改它以便它只访问数据库一次?

c# - 一键存储Session中的多个值——Session的可能列表

c# - 取消不接受 CancellationToken 的异步操作的正确方法是什么?

c# - 模拟 ApiController

c# - 在 Linux 中使用带有 DbContext 的 Entity Framework 有问题

azure - 响应式、长时间运行的序列和云中的持久性