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