【问题标题】:Is a Subject in RX.Net always harmful?RX.Net 中的主题总是有害的吗?
【发布时间】:2014-05-26 03:22:21
【问题描述】:

我正在与一位同事交谈,他向我指出了关于 subjects being considered harmful 的 SO 问题。但是,我有两种情况,我有一些非确定性代码,在其他情况下似乎不合理。

非标准事件:

 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))

主题没有暴露,只是通过一个可观察的。是否有另一条路线建议不是大量的样板文件?

【问题讨论】:

  • 简短的回答是否定的。但是,这两种情况都可以使用内置功能来处理。 IObservable<T> ToObservable(this Task<T> task) 应该处理您的任务继续情况,Observable.FromEvent 应该处理其他情况。这些方法是否过于冗长?两者都提供了比简单主题更多的功能,包括懒惰。
  • @ChristopherHarris 谢谢,但我不确定第一个有效,我知道第二个无效。第一个是因为我的任务数量不确定,第二个是因为如前所述,这不是标准事件……FromEvent 不起作用
  • 当您说“所有并行运行的任务数量不确定”时,您真正的意思是“多个急切调用的任务”,不是吗?
  • @ChristopherHarris 是的。他们可以在不同的时间开始,否则合并会起作用
  • 您的非标准活动的委托类型是什么?

标签: c# system.reactive reactive-programming


【解决方案1】:

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

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

【讨论】:

  • 请参阅上面我对@ChristopherHarris 的评论,因为这两个选项都不适合我
【解决方案2】:

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 & 合并

如果您已经可以访问所有任务,则可以将它们转换为 Observable,然后将它们合并为单个 observable。

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();
    }
}

合并 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();
    }
}

主题

为什么要使用或不使用主题是我没有时间充分回答的问题。但是,通常来说,我发现当运算符似乎不存在时,使用 Subject 往往是“简单的出路”。

如果您可以通过某种方式限制某个主题对应用程序其余部分的可见性,那么请务必使用主题并这样做。但是,如果您正在寻找消息总线功能,则应该重新考虑应用程序的设计,因为消息总线是反模式。

【讨论】:

    【解决方案3】:

    受试者无害。这对我来说可能有点太教条了(我是第一个对主题的使用嘘声)。我会说主题表示代码气味。没有它们你可能会做得更好,但如果你把封装的东西放在你的班级里,那么至少你把气味放在一个地方。

    在这里我想说的是,您已经在使用“非标准”事件模式,而且您似乎不想或不能更改它。在这种情况下,使用主题作为桥梁似乎不会让它变得更糟。

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

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

    【讨论】:

      【解决方案4】:

      以下是一本关于 Rx 的好书关于主题为何以及何时有害的内容:

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

      "避免使用主题类型。Rx 实际上是一个函数式 编程范式。使用主题意味着我们现在正在管理状态, 这可能会发生变异。处理变异状态和 同时异步编程很难做到正确。 此外,许多运算符(扩展方法)已经 精心编写,以确保正确和一致的寿命 订阅和序列得到维护;当你介绍 科目,你可以打破这个。未来的版本也可能会很重要 如果您明确使用主题,性能会下降。”

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-11-24
        • 2010-11-08
        • 1970-01-01
        • 1970-01-01
        • 2010-10-09
        • 2019-11-23
        • 2012-04-30
        • 2011-05-21
        相关资源
        最近更新 更多