Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在RX中发布到多个订阅_C#_.net_System.reactive - Fatal编程技术网

C# 在RX中发布到多个订阅

C# 在RX中发布到多个订阅,c#,.net,system.reactive,C#,.net,System.reactive,我正在研究如何为一个项目开发一个插件框架,Rx似乎非常适合我所要实现的目标。最终,该项目将是一组插件(模块化功能),可以通过xml进行配置以完成不同的任务。要求如下 即使在插件中也要实施模块化体系结构。这鼓励了松散耦合,并潜在地将复杂性降至最低。这有望使单个插件功能更易于建模和测试 强制数据的不变性,以降低复杂性,并确保模块内的状态管理保持在最低限度 尽可能提供线程池线程以在模块内工作,从而阻止手动创建线程 在我看来,插件本质上是一个数据转换实体。这意味着一个插件 接收一些数据并以某种方式对其

我正在研究如何为一个项目开发一个插件框架,Rx似乎非常适合我所要实现的目标。最终,该项目将是一组插件(模块化功能),可以通过xml进行配置以完成不同的任务。要求如下

  • 即使在插件中也要实施模块化体系结构。这鼓励了松散耦合,并潜在地将复杂性降至最低。这有望使单个插件功能更易于建模和测试
  • 强制数据的不变性,以降低复杂性,并确保模块内的状态管理保持在最低限度
  • 尽可能提供线程池线程以在模块内工作,从而阻止手动创建线程
  • 在我看来,插件本质上是一个数据转换实体。这意味着一个插件

    • 接收一些数据并以某种方式对其进行转换以生成新数据(此处未显示)
    • 自行生成数据并将其发送给观察者
    • 接收一些数据并在不通知外部人员的情况下对数据进行处理
    如果你进一步理解这个概念,一个插件可以由以上三种类型组成。例如,在一个插件中,你可以有一个IntGenerator模块,该模块生成一些数据到ConsoleWorkUnit模块等。因此,我试图在主函数中建模的是插件必须执行其工作的接线

    为此,我使用来自Microsoft的不可变nuget创建了以下基类。我试图实现的是抽象掉Rx调用,以便它们可以在模块中使用,因此最终目标是将对缓冲区等的调用封装在抽象类中,这些抽象类可以用来组成复杂的查询和模块。通过这种方式,代码比实际读取模块中的所有代码,发现它订阅了x类型的缓冲区或窗口等,更具有自文档性

    public abstract class OutputBase<TOutput> : SendOutputBase<TOutput>
    {
        public abstract void Work();
    }
    
    public interface IBufferedBase<TOutput>
    {
        void Work(IList<ImmutableList<Data<TOutput>>> list);
    }
    
    public abstract class BufferedWorkBase<TInput> : IBufferedBase<TInput>
    {
        public abstract void Work(IList<ImmutableList<Data<TInput>>> input);
    }
    public abstract class SendOutputBase<TOutput>
    {
        private readonly ReplaySubject<ImmutableList<Data<TOutput>>> _outputNotifier;
        private readonly IObservable<ImmutableList<Data<TOutput>>> _observable;
    
        protected SendOutputBase()
        {
            _outputNotifier = new ReplaySubject<ImmutableList<Data<TOutput>>>(10);
            _observable  =  _outputNotifier.SubscribeOn(ThreadPoolScheduler.Instance);
            _observable = _outputNotifier.ObserveOn(ThreadPoolScheduler.Instance);
        }
    
        protected void SetOutputTo(ImmutableList<Data<TOutput>> output)
        {
            _outputNotifier.OnNext(output);
        }
    
        public void ConnectOutputTo(IWorkBase<TOutput> unit)
        {
            _observable.Subscribe(unit.Work);
        }
    
        public void BufferOutputTo(int count, IBufferedBase<TOutput> unit)
        {
            _observable.Buffer(count).Subscribe(unit.Work);
        }
    }
    
    public abstract class WorkBase<TInput> : IWorkBase<TInput>
    {
        public abstract void Work(ImmutableList<Data<TInput>> input);
    }
    
    public interface IWorkBase<TInput>
    {
        void Work(ImmutableList<Data<TInput>> input);
    }
    
    public class Data<T>
    {
        private readonly T _value;
    
        private Data(T value)
        {
            _value = value;
        }
    
        public static Data<TData> Create<TData>(TData value)
        {
            return new Data<TData>(value);
        }
    
        public T Value { get { return _value; } }
    
    }
    

    此架构合理吗?

    您正在缓冲您的可观察对象(
    .Buffer(count)
    ),以便它仅在
    计数
    通知到达后发出信号

    但是,您的
    IntGenerator.DoWork
    只生成一个值。因此,您永远不会“填充”缓冲区并触发下游通知


    要么更改
    DoWork
    ,使其最终生成更多值,要么在完成其工作时让其完成可观察流<代码>缓冲区将在流完成时释放剩余的缓冲值。为此,这意味着
    IntGenerator.DoWork
    需要在某个地方调用
    \u outputNotifier.OnCompleted()

    我尝试运行您的代码,但找不到
    IBufferedBase
    BufferedWorkBase
    的定义。您可以添加这些吗?另外,Rx调用几乎总是流畅的-因此调用此
    \u outputNotifier.SubscribeOn(ThreadPoolScheduler.Instance)
    只会返回一个新的
    IObservable
    ,您会丢弃它。与
    \u outputNotifier.ObserveOn(ThreadPoolScheduler.Instance)
    相同。您可能想先尝试修复这些问题。@Enigmativity感谢您的响应,并按照建议使用接口和更改的代码进行了更新。干杯,你还没有掌握流利的界面用法。当您分配
    ObserveOn
    时,您正在擦除
    subscribebeon
    。非常感谢您发布代码。看来你正在努力使Rx尽可能的硬。Rx是一个非常实用的程序(就像在函数式编程中一样),但您正试图使其面向对象。你们失去了很多能量。你能从需求的角度解释一下你在这里要做什么吗?我想我可以让这一切变得更容易。谢谢你!你完全正确。我已经更新了代码,它按预期工作。在我当前的架构中,是否有可能在创建枚举时对其进行缓冲(这是我的初衷)?我认为您的回答解决了问题的初衷,因此我会将其标记为已回答并创建一个新的。再次感谢你的帮助对不起,我不在家。不要做一个
    主题
    ,只需做一个
    主题
    ,然后用你的
    DoWork
    方法将各个项目推到主题中。产生的可观测结果将是
    IObservable
    。此时,
    Buffer
    将产生所需的效果,即生成
    count
    项的数组:
    IObservable
    。如果您确实想要一个
    不可变列表
    ,请使用
    跟随
    缓冲区
    。选择(b=>ImmutableList.CreateRange(b))
    public class IntGenerator : OutputBase<int>
    {
        public override void Work()
        {
            var list = ImmutableList<Data<int>>.Empty;
            var builder = list.ToBuilder();
            for (var i = 0; i < 1000; i++)
            {
                builder.Add(Data<int>.Create(i));
            }
    
            SetOutputTo(builder.ToImmutable());
        }
    }
    
    public class ConsoleWorkUnit : WorkBase<int>
    {
        public override void Work(ImmutableList<Data<int>> input)
        {
            foreach (var data in input)
            {
                Console.WriteLine("ConsoleWorkUnit printing {0}", data.Value);
            }
        }
    }
    
    public class SumPrinter : WorkBase<int>
    {
    
        public override void Work(ImmutableList<Data<int>> input)
        {
            input.ToObservable().Buffer(2).Subscribe(PrintSum);
        }
    
        private void PrintSum(IList<Data<int>> obj)
        {
          Console.WriteLine("Sum of {0}, {1} is {2} ", obj.First().Value,obj.Last().Value ,obj.Sum(x=>x.Value) );
        }
    }
    
            var intgen = new IntGenerator();
            var cons = new ConsoleWorkUnit();
            var sumPrinter = new SumPrinter();
    
            intgen.ConnectOutputTo(cons);
            intgen.BufferOutputTo(3,sumPrinter);
    
            Task.Factory.StartNew(intgen.Work);
    
            Console.ReadLine();