RX.Net中的主题是否总是有害的?

时间:2014-05-26 03:22:21

标签: c# system.reactive reactive-programming

我正在和一位同事交谈,他向我提出了关于subjects being considered harmful的问题。但是,我有两种情况,我有一些非确定性的代码,似乎没有任何其他方式合理。

非标准事件:

 event handler(class, result)
 {
   subject.OnNext(result);
 }

 public delegate void _handler
   ([MarshalAs(UnmanagedType.Interface), In] MyClass class, 
    [MarshalAs(UnmanagedType.Interface), In] ResultClass result)

并行任务(非确定性任务数量并行运行,从不同时间开始)

 Task.Start(()=> ...).ContinueWith(prevTask => subject.OnNext(prevTask.result))

只有通过观察才能暴露受试者。还有另一条路线建议不是很多样板吗?

4 个答案:

答案 0 :(得分:6)

受试者并非总是有害的。即使在Rx本身内,它们也有许多合法用途。然而,很多时候一个人去使用主题,已经为该场景编写了一个强大的Rx方法(它可能会也可能不会在内部使用主题)。您的2个示例就是这种情况。查看Task.ToObservable和Observable.FromEventPattern。

另一个常见的案例主题被滥用是指开发人员将流分成两部分。他们确信他们需要订阅流,并且在回调中他们为新流生成数据。他们用主题做这件事。但通常他们应该使用Select代替。

答案 1 :(得分:1)

Observable.FromEvent

System.FromEvent不仅适用于内置事件类型:您只需要使用正确的重载。

class Program
{
    private static event Action<int> MyEvent;

    public static void Main(string[] args)
    {
        Observable.FromEvent<int>(
            (handler) => Program.MyEvent += handler,
            (handler) => Program.MyEvent -= handler
            )
            .Subscribe(Console.WriteLine);

        Program.MyEvent(5);

        Console.ReadLine();
    }
}

Task.ToObservable&amp;合并

如果您已经可以访问所有任务,则可以将它们转换为Observables,并将它们合并为一个可观察对象。

class Program
{
    public static void Main(string[] args)
    {
        Observable.Merge(
                // Async / Await
                (
                    (Func<Task<string>>)
                    (async () => { await Task.Delay(250); return "async await"; })
                )().ToObservable(),
                // FromResult
                Task.FromResult("FromResult").ToObservable(),
                // Run
                Task.Run(() => "Run").ToObservable()
            )
            .Subscribe(Console.WriteLine);

        Console.ReadLine();
    }
}

Merge Observable

或者,如果您没有预先完成所有任务,您仍然可以使用Merge,但是您需要某种方式来传达未来的任务。在这种情况下,我使用了一个主题,但您应该使用最简单的Observable来表达这一点。如果这是一个主题,那么一定要使用一个主题。

class Program
{
    public static void Main(string[] args)
    {
        // We use a subject here since we don't have all of the tasks yet.
        var tasks = new Subject<Task<string>>();

        // Make up some tasks.
        var fromResult = Task.FromResult("FromResult");
        var run = Task.Run(() => "Run");
        Func<Task<string>> asyncAwait = async () => {
            await Task.Delay(250);
            return "async await";
        };

        // Merge any future Tasks into an observable, and subscribe.
        tasks.Merge().Subscribe(Console.WriteLine);

        // Send tasks.
        tasks.OnNext(fromResult);
        tasks.OnNext(run);
        tasks.OnNext(asyncAwait());

        Console.ReadLine();
    }
}

受试者

为什么使用或不使用主题是一个我没有时间充分回答的问题。然而,通常来说,我发现当看起来操作员不存在时,使用主题往往是“简单的出路”。

如果您可以某种方式限制某个主体对其他应用程序的可见性,那么无论如何都要使用主题并且这样做。但是,如果您正在寻找消息总线功能,则应重新考虑应用程序的设计,因为消息总线是反模式的。

答案 2 :(得分:1)

受试者没有害处。这对我来说甚至可能有点过于教条(我首先要对主题的使用进行嘘声)。我会说受试者表示代码味道。如果没有它们,你可能会做得更好,但是如果你把它封装在你的班级中,那么至少你要把气味保存在一个地方。

我会说,你已经在使用&#34;非标准&#34;事件模式,似乎你不想或不能改变它。在这种情况下,似乎使用主体作为桥梁并不会使它变得更糟。

如果你是从头开始,那么我建议你深入思考你的设计,你可能会发现你不需要一个主题。

最后,我同意其他评论,你应该使用FromEvent和ToTask,但你建议这些不起作用。为什么?我不认为你提供足够的代码库来帮助解决这样的设计问题。例如你是如何创建非确定性任务的?什么?你想要解决的实际问题是什么?如果你能提供一个完整的例子,你可能会得到你正在寻找的关注量。

答案 3 :(得分:0)

以下是文档中说明其为何有害的原因:

http://www.introtorx.com/Content/v1.0.10621.0/18_UsageGuidelines.html

  

“避免使用主题类型。Rx实际上是一种功能   编程范例。使用主体意味着我们现在正在管理状态,   这可能会变异。处理变异状态和   同时很难进行异步编程。   此外,许多运算符(扩展方法)已经   仔细撰写以确保正确和一致的使用寿命   订阅和顺序得以维护;当你介绍   科目,你可以打破这一点。将来的发行版也可能会很重要   如果您明确使用主题,则会降低性能。”