c#中的IObserver和IObservable,用于观察者vs委托,事件

本文关键字:观察者 vs 委托 事件 用于 IObserver IObservable 中的 | 更新日期: 2023-09-27 18:17:46

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

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

我们有一个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还是我为什么要用IObservable

c#中的IObserver和IObservable,用于观察者vs委托,事件

这是一个修改的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();
        }
    }

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

更新:ReactiveX已经被翻译成许多平台和语言,现在作为一个开源项目进行管理。这是登陆页面。

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

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实现中嵌入这些订阅,以更紧密地反映你的代码。但希望这能让你了解如何使用Rx