【问题标题】:IObserver and IObservable in C# for Observer vs Delegates, EventsC# 中的 IObserver 和 IObservable 用于观察者与代表、事件
【发布时间】:2013-06-10 08:46:53
【问题描述】:

我要做的只是实现观察者模式。

所以,我想出了这个解决方案:

我们有一个 PoliceHeadQuarters,其主要工作是向所有订阅它的人发送通知。考虑到 DSP、Inspector 和 SubInspector 类订阅了 PoliceHeadQuarters。

使用我编写的事件和委托

public class HeadQuarters 
{
    public delegate void NewDelegate(object sender, EventArgs e);
    public event EventHandler NewEvent;
    public void RaiseANotification()
    {
        var handler = this.NewEvent;
        if (handler != null)
        {
            handler(this, new EventArgs());
        }
    }
}

public class SubInspector
{
    public void Listen(object sender, EventArgs e)
    {
        MessageBox.Show(string.Format("Event Notification received by sender = {0} with eventArguments = {1}", sender, e.ToString()));
    }
}

public class Inspector
{
    public void Listen(object sender, EventArgs e)
    {
        MessageBox.Show(string.Format("Event Notification received by sender = {0} with eventArguments = {1}", sender, e.ToString()));
    }
}

这就是我调用它的方式

       var headQuarters = new HeadQuarters();
        var SubInspector = new SubInspector();
        var Inspector = new Inspector();
        headQuarters.NewEvent += Inspector.Listen;
        headQuarters.NewEvent += SubInspector.Listen;
        headQuarters.RaiseANotification();

因此,只要调用 RaiseANotification() 函数,Inspector 和 SubInspector 类都会收到通知。

DotNet Framework 4、4.5 似乎支持了一种新的方式,叫做 IObserver 和 IObservable。

谁能给我一个在上述场景中使用 IObservable 和 IObserver 模式的超级简单示例?我用谷歌搜索只是发现互联网上的可用示例过于臃肿且难以理解。

我的小窍门:(可能我认为这是错误的)

  class DSP : IObserver //since it observes the headquarters ?
  class PoliceHeadQuarters: IObservable // since here's where we send the notifications ?

提前致谢。

编辑:有人还说 MSDN 文档对于 IObservable @ 也是不正确的 IObservable vs Plain Events or Why Should I use IObservable?.

【问题讨论】:

  • msdn.microsoft.com/en-us/library/dd990377.aspx - 有一个很好的例子,你为什么不尝试编译并运行它?
  • @Spook:问题实际上是我无法将我的场景与这些示例联系起来。任何骨架代码结构都应该可以帮助我走得更远..
  • 看起来微软的例子是使用一个基本的事件聚合器。一种更复杂但最终更灵活的方法。 Aggregator 迭代 IObserver 的类型,按顺序调用它们。我认为这就是为什么使用基于接口的方法而不是委托的原因。
  • @DavidOsborne:是的,有点复杂。初学者有什么简单的例子吗?或者非常感谢此场景的任何骨架代码!
  • 在这里查看 Jeremy Miller 文章中的“直接通信”部分:codebetter.com/jeremymiller/2007/06/04/… 他很好地概述了接口/委托方法的优缺点。

标签: c# design-patterns .net-4.5 system.reactive


【解决方案1】:

以下是 MSDN 示例的修改以适合您的框架:

    public struct Message
    {
        string text;

        public Message(string newText)
        {
            this.text = newText;
        }

        public string Text
        {
            get
            {
                return this.text;
            }
        }
    }

    public class Headquarters : IObservable<Message>
    {
        public Headquarters()
        {
            observers = new List<IObserver<Message>>();
        }

        private List<IObserver<Message>> observers;

        public IDisposable Subscribe(IObserver<Message> observer)
        {
            if (!observers.Contains(observer))
                observers.Add(observer);
            return new Unsubscriber(observers, observer);
        }

        private class Unsubscriber : IDisposable
        {
            private List<IObserver<Message>> _observers;
            private IObserver<Message> _observer;

            public Unsubscriber(List<IObserver<Message>> observers, IObserver<Message> observer)
            {
                this._observers = observers;
                this._observer = observer;
            }

            public void Dispose()
            {
                if (_observer != null && _observers.Contains(_observer))
                    _observers.Remove(_observer);
            }
        }

        public void SendMessage(Nullable<Message> loc)
        {
            foreach (var observer in observers)
            {
                if (!loc.HasValue)
                    observer.OnError(new MessageUnknownException());
                else
                    observer.OnNext(loc.Value);
            }
        }

        public void EndTransmission()
        {
            foreach (var observer in observers.ToArray())
                if (observers.Contains(observer))
                    observer.OnCompleted();

            observers.Clear();
        }
    }

    public class MessageUnknownException : Exception
    {
        internal MessageUnknownException()
        {
        }
    }

    public class Inspector : IObserver<Message>
    {
        private IDisposable unsubscriber;
        private string instName;

        public Inspector(string name)
        {
            this.instName = name;
        }

        public string Name
        {
            get
            {
                return this.instName;
            }
        }

        public virtual void Subscribe(IObservable<Message> provider)
        {
            if (provider != null)
                unsubscriber = provider.Subscribe(this);
        }

        public virtual void OnCompleted()
        {
            Console.WriteLine("The headquarters has completed transmitting data to {0}.", this.Name);
            this.Unsubscribe();
        }

        public virtual void OnError(Exception e)
        {
            Console.WriteLine("{0}: Cannot get message from headquarters.", this.Name);
        }

        public virtual void OnNext(Message value)
        {
            Console.WriteLine("{1}: Message I got from headquarters: {0}", value.Text, this.Name);
        }

        public virtual void Unsubscribe()
        {
            unsubscriber.Dispose();
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            Inspector inspector1 = new Inspector("Greg Lestrade");
            Inspector inspector2 = new Inspector("Sherlock Holmes");

            Headquarters headquarters = new Headquarters();

            inspector1.Subscribe(headquarters);
            inspector2.Subscribe(headquarters);

            headquarters.SendMessage(new Message("Catch Moriarty!"));
            headquarters.EndTransmission();

            Console.ReadKey();
        }
    }

【讨论】:

  • 不管检查官抓到Professor没抓到Professor,我现在应该能抓到Pattern了。非常感谢。
  • 很高兴我能帮上忙。祝你好运!
  • 好在 .Net GC 可以处理循环引用,否则这段代码会像地狱一样泄漏。
  • 非常清晰的例子,帮助我理解了一些概念,非常感谢。
【解决方案2】:

另一个建议 - 您可能需要考虑将响应式扩展库用于任何使用 IObservable 的代码。 nuget 包是 Rx-Main,它的主页在这里:http://msdn.microsoft.com/en-us/data/gg577609.aspx

这将为您节省大量样板代码。这是一个超级简单的例子:

var hq = new Subject<string>();

var inspectorSubscription = hq.Subscribe(
    m => Console.WriteLine("Inspector received: " + m));

var subInspectorSubscription = hq.Subscribe(
    m => Console.WriteLine("Sub Inspector received: " + m));

hq.OnNext("Catch Moriarty!");

它会输出:

Inspector received: Catch Moriarty!
Sub Inspector received: Catch Moriarty!

响应式扩展是一个很大的主题,也是一个非常强大的库 - 值得研究。我推荐上面链接中的动手实验室。

您可能希望将这些订阅嵌入到您的 Inspector、SubInspector immplementatinos 中,以更准确地反映您的代码。但希望这能让您深入了解您可以使用 Rx 做什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-17
    • 1970-01-01
    • 1970-01-01
    • 2013-01-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多