C# 多播和订阅主题的被动框架问题

C# 多播和订阅主题的被动框架问题,c#,system.reactive,C#,System.reactive,我刚刚开始学习如何使用反应式框架,并且正在努力实现多播发布到多个订阅者 我的一切都很顺利,就像这样: m_MessagePublisher = m_ServerClient.MessageQueue .GetConsumingEnumerable() .ToObservable(TaskPoolScheduler.Default); var genericServerMessageSubscriber = m_MessagePublisher .Where(

我刚刚开始学习如何使用反应式框架,并且正在努力实现多播发布到多个订阅者

我的一切都很顺利,就像这样:

m_MessagePublisher = m_ServerClient.MessageQueue
      .GetConsumingEnumerable()
      .ToObservable(TaskPoolScheduler.Default);

var genericServerMessageSubscriber = m_MessagePublisher
      .Where(message => message is GenericServerMessage)
      .Subscribe(message =>
      {
          // do something here
      }
但后来我意识到这不支持多播,当我尝试连接另一个本应被同一消息击中的订户时,它不会触发。我一直在阅读.MultiCast扩展,并试图弄清楚主题是如何在这方面发挥作用的,但还未能使其发挥作用:

var subject = new Subject<BesiegedMessage>();

var messagePublisher = m_ServerClient.MessageQueue
      .GetConsumingEnumerable()
      .ToObservable(TaskPoolScheduler.Default)
      .Multicast(subject);

// All generic server messages are handled here
var genericServerMessageSubscriber = subject
      .Where(message => message is GenericServerMessage)
      .Subscribe(message =>
      {
            // do something here
      }
var subject=new subject();
var messagePublisher=m_ServerClient.MessageQueue
.getconsumineGenumerable()
.ToObservable(TaskPoolScheduler.Default)
.多播(主题);
//所有通用服务器消息都在此处处理
var genericServerMessageSubscriber=subject
.Where(message=>message是GenericServerMessage)
.订阅(消息=>
{
//在这里做点什么
}
但是现在没有一个订阅者受到攻击,包括一个以前工作正常的订阅者。为了能够正确地多播到多个订阅者,我在这里遗漏了什么

更新:使用Subscribe(subject)而不是Multicast(subject)似乎对Multicast起到了作用,这让我非常困惑.Multicast()用于编辑什么:

哈哈-我读得太快了,这对我很有好处-你问的是简单得多…也就是说,我认为下面的内容很重要,所以我就不说了…所以,你的问题-试着加上这一行:

var messagePublisher = m_ServerClient.MessageQueue
  .GetConsumingEnumerable()
  .ToObservable(TaskPoolScheduler.Default)
  .Multicast(subject)
  // Here: connectable observables are a PITA...
  .RefCount();
结束编辑:

嗯…如何描述
多播
…我想让我们举个例子:

假设你有这样的东西,你认为它能产生什么

int delay = 100;
var source = Observable.Interval(TimeSpan.FromMilliseconds(delay));
var publishingFrontend = new Subject<string>();

// Here's "raw"
var rawStream = source;
using(rawStream.Subscribe(x => Console.WriteLine("{0}", x)))
{
    Thread.Sleep(delay * 3);
    using(rawStream.Subscribe(x => Console.WriteLine("Inner: {0}", x)))
    {
        Thread.Sleep(delay * 3);
    }
    Thread.Sleep(delay * 5);
}
嗯……所以如果我们想“在中流中打交道”,我们使用
Publish().RefCount()
模式:

var singleSource = source.Publish().RefCount();
using(singleSource.Subscribe(x => Console.WriteLine("{0}", x)))
{
    Thread.Sleep(delay * 3);
    using(singleSource.Subscribe(x => Console.WriteLine("Inner: {0}", x)))
    {
        Thread.Sleep(delay * 3);
    }
    Thread.Sleep(delay * 5);
}
这会产生如下结果:

0
1
2
Inner: 2
3
Inner: 3
4
Inner: 4
5
6
7
8
9
假设我们没有
Publish()
操作符-我们如何模拟它

但是还有另一种方法

编辑:

事实上,所有生成扩展的
ConnectableObservable
都依赖于
多播
/
主题
配对:

Publish() => Multicast(new Subject<T>)
Replay() => Multicast(new ReplaySubject<T>)
PublishLast() => Multicast(new AsyncSubject<T>)
Publish()=>多播(新主题)
Replay()=>多播(新ReplaySubject)
PublishLast()=>多播(新的AsyncSubject)

有没有等待问题的答案?前几天我刚刚向一位同事解释了多播,因此我快速输入了(非序列)初始响应,但此后我进行了编辑。:)这肯定需要一种“颠倒”的思维方式——特别是,随着时间的推移,声明数据的形状,就像陶工在陶土中一样,一路修补它。玩得开心:)我想如果你的源代码是IObservable的,你可以把(msg=>msg是GenericServerMessage)的位置换成OfType()或Cast()。他真的是在
.Publish().RefCount()之后吗
而不是
多播
,这样他就不必制作自己没有特定用途的主题了?@Brandon
Publish
实际上在引擎盖下使用了
多播
——基本上是相同的代码,只是一个是另一个的缩写。而且,如果他使用了主题,就不需要变量,只需在Mulitcast操作符中更新它…然后将您带回到仅使用发布。当您想使用其他主题时,多播确实适用。@leecampbell true!尽管内存可用,但每个多播/主题对都有一个等价项:异步,等等-我必须检查我的注释以获得精确的映射。@LeeCampbell-Aha,找到了mah-notes!在答案末尾添加了一个介绍配对的简介。
Console.WriteLine("Simulated Publish:");
// use a subject to proxy values...
var innerSubject = new Subject<long>();
// wire up the source to "write to" the subject
var innerSub = source.Subscribe(innerSubject);
var simulatedSingleSource = Observable.Create<long>(obs =>
{
    // return subscriptions to the "proxied" subject
    var publishPoint = innerSubject.Subscribe(obs);        
    return publishPoint;
});
Simulated Publish:
0
1
2
Inner: 2
3
Inner: 3
4
Inner: 4
5
6
7
8
9
Console.WriteLine("MulticastPublish:");
var multicastPublish = source.Multicast(new Subject<long>()).RefCount();    
using(multicastPublish.Subscribe(x => Console.WriteLine("{0}", x)))
{
    Thread.Sleep(delay * 3);
    using(multicastPublish.Subscribe(x => Console.WriteLine("Inner: {0}", x)))
    {
        Thread.Sleep(delay * 3);
    }
    Thread.Sleep(delay * 5);
}
MulticastPublish:
0
1
2
Inner: 2
3
Inner: 3
4
Inner: 4
5
6
7
8
9
Publish() => Multicast(new Subject<T>)
Replay() => Multicast(new ReplaySubject<T>)
PublishLast() => Multicast(new AsyncSubject<T>)