IObserver 和 IObservable 在 C# 中用于观察者 vs 委托、事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17020011/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 08:22:01  来源:igfitidea点击:

IObserver and IObservable in C# for Observer vs Delegates, Events

c#design-patterns.net-4.5system.reactive

提问by now he who must not be named.

All I am trying to do is implementing the observer pattern.

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

So, I came up with this solution:

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

We have a PoliceHeadQuarters whose primary job is to send notifications to all those who are subscribed to it. Consider that the DSP, Inspector and SubInspector classes are subscribed to PoliceHeadQuarters.

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

Using Events and Delegates I wrote

使用我写的事件和委托

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()));
    }
}

and this is how I invoked it

这就是我调用它的方式

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

so, both Inspector and SubInspector classes get notification whenever there the function RaiseANotification() is invoked.

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

It seems that the DotNet Framework 4, 4.5 supports a new way called IObserver and IObservable.

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

Can anyone give me a super simple example using IObservable and IObserver pattern for the above scenario? I googled only to find the available examples in the internet too bloated and difficult to understand.

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

My hinch: (probably i think it's wrong)

我的想法:(可能我认为这是错误的)

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

Thanks in advance.

提前致谢。

EDIT: Somebody also said that the MSDN documentation is also incorrect for IObservable @ IObservable vs Plain Events or Why Should I use IObservable?.

编辑:有人还说 MSDN 文档对于 IObservable @ IObservable vs Plain Events 或为什么我应该使用 IObservable也是不正确的 .

采纳答案by Spook

Here's a modification of MSDN example to fit your framework:

这是 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();
        }
    }

回答by James World

Another suggestion - you probably want to consider leveraging the reactive extensions library for any code using IObservable. The nuget package is Rx-Main and the homepage for it is here: http://msdn.microsoft.com/en-us/data/gg577609.aspx

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

This will save you a lot of boilerplate code. Here's a super simple example:

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

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!");

It will output:

它会输出:

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

Reactive Extensions is a big subject, and a very powerful library - worth investigating. I recommend the hands-on lab from the link above.

Reactive Extensions 是一个很大的主题,也是一个非常强大的库——值得研究。我从上面的链接推荐动手实验室。

You would probably want to embed those subscriptions within your Inspector, SubInspector immplementatinos to more closely reflect your code. But hopefully this gives you an insight into what you can do with Rx.

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