带有委托的 C# 观察者/观察者的超简单示例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1249517/
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-06 14:14:27  来源:igfitidea点击:

Super-simple example of C# observer/observable with delegates

c#eventsdelegatesobserver-pattern

提问by Deniz Dogan

I recently started digging into C# but I can't by my life figure out how delegates work when implementing the observer/observable pattern in the language.

我最近开始深入研究 C#,但我一生都无法弄清楚在语言中实现观察者/可观察模式时委托是如何工作的。

Could someone give me a super-simple example of how it is done? I havegoogled this, but all of the examples I found were either too problem-specific or too "bloated".

有人可以给我一个超级简单的例子来说明它是如何完成的吗?我谷歌上搜索过这个,但我发现的所有例子要么过于针对特定问题,要么过于“臃肿”。

采纳答案by Jon Skeet

The observer pattern is usually implemented with events.

观察者模式通常用事件实现。

Here's an example:

下面是一个例子:

using System;

class Observable
{
    public event EventHandler SomethingHappened;

    public void DoSomething() =>
        SomethingHappened?.Invoke(this, EventArgs.Empty);
}

class Observer
{
    public void HandleEvent(object sender, EventArgs args)
    {
        Console.WriteLine("Something happened to " + sender);
    }
}

class Test
{
    static void Main()
    {
        Observable observable = new Observable();
        Observer observer = new Observer();
        observable.SomethingHappened += observer.HandleEvent;

        observable.DoSomething();
    }
}

See the linked article for a lot more detail.

有关更多详细信息,请参阅链接的文章。

Note that the above example uses C# 6 null-conditionaloperator to implement DoSomethingsafely to handle cases where SomethingHappenedhas not been subscribed to, and is therefore null. If you're using an older version of C#, you'd need code like this:

请注意,上面的示例使用 C# 6空条件运算符来DoSomething安全地实现以处理SomethingHappened尚未订阅的情况,因此为空。如果您使用的是旧版本的 C#,则需要这样的代码:

public void DoSomething()
{
    var handler = SomethingHappened;
    if (handler != null)
    {
        handler(this, EventArgs.Empty);
    }
}

回答by Lasse V. Karlsen

Here's a simple example:

这是一个简单的例子:

public class ObservableClass
{
    private Int32 _Value;

    public Int32 Value
    {
        get { return _Value; }
        set
        {
            if (_Value != value)
            {
                _Value = value;
                OnValueChanged();
            }
        }
    }

    public event EventHandler ValueChanged;

    protected void OnValueChanged()
    {
        if (ValueChanged != null)
            ValueChanged(this, EventArgs.Empty);
    }
}

public class ObserverClass
{
    public ObserverClass(ObservableClass observable)
    {
        observable.ValueChanged += TheValueChanged;
    }

    private void TheValueChanged(Object sender, EventArgs e)
    {
        Console.Out.WriteLine("Value changed to " +
            ((ObservableClass)sender).Value);
    }
}

public class Program
{
    public static void Main()
    {
        ObservableClass observable = new ObservableClass();
        ObserverClass observer = new ObserverClass(observable);
        observable.Value = 10;
    }
}

Note:

笔记:

  • This violates a rule in that I don't unhook the observer from the observable, this is perhaps good enough for this simple example, but make sure you don't keep observers hanging off of your events like that. A way to handle this would be to make ObserverClass IDisposable, and let the .Dispose method do the opposite of the code in the constructor
  • No error-checking performed, at least a null-check should be done in the constructor of the ObserverClass
  • 这违反了一条规则,因为我不会将观察者从 observable 中解开,这对于这个简单的例子来说可能已经足够了,但是请确保您不要让观察者像那样挂在你的事件上。处理此问题的一种方法是使 ObserverClass IDisposable,并让 .Dispose 方法执行与构造函数中的代码相反的操作
  • 没有执行错误检查,至少应该在 ObserverClass 的构造函数中进行空检查

回答by Jesse C. Slicer

I've tied together a couple of the great examples above (thank you as always to Mr. Skeetand Mr. Karlsen) to include a couple of different Observables and utilized an interface to keep track of them in the Observer and allowed the Observer to to "observe" any number of Observables via an internal list:

我将上面的几个很好的例子(一如既往地感谢Skeet 先生Karlsen 先生)捆绑在一起,以包含几个不同的 Observable 并利用一个界面在观察者中跟踪它们,并允许观察者通过内部列表“观察”任意数量的 Observable:

namespace ObservablePattern
{
    using System;
    using System.Collections.Generic;

    internal static class Program
    {
        private static void Main()
        {
            var observable = new Observable();
            var anotherObservable = new AnotherObservable();

            using (IObserver observer = new Observer(observable))
            {
                observable.DoSomething();
                observer.Add(anotherObservable);
                anotherObservable.DoSomething();
            }

            Console.ReadLine();
        }
    }

    internal interface IObservable
    {
        event EventHandler SomethingHappened;
    }

    internal sealed class Observable : IObservable
    {
        public event EventHandler SomethingHappened;

        public void DoSomething()
        {
            var handler = this.SomethingHappened;

            Console.WriteLine("About to do something.");
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
    }

    internal sealed class AnotherObservable : IObservable
    {
        public event EventHandler SomethingHappened;

        public void DoSomething()
        {
            var handler = this.SomethingHappened;

            Console.WriteLine("About to do something different.");
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }
    }

    internal interface IObserver : IDisposable
    {
        void Add(IObservable observable);

        void Remove(IObservable observable);
    }

    internal sealed class Observer : IObserver
    {
        private readonly Lazy<IList<IObservable>> observables =
            new Lazy<IList<IObservable>>(() => new List<IObservable>());

        public Observer()
        {
        }

        public Observer(IObservable observable) : this()
        {
            this.Add(observable);
        }

        public void Add(IObservable observable)
        {
            if (observable == null)
            {
                return;
            }

            lock (this.observables)
            {
                this.observables.Value.Add(observable);
                observable.SomethingHappened += HandleEvent;
            }
        }

        public void Remove(IObservable observable)
        {
            if (observable == null)
            {
                return;
            }

            lock (this.observables)
            {
                observable.SomethingHappened -= HandleEvent;
                this.observables.Value.Remove(observable);
            }
        }

        public void Dispose()
        {
            for (var i = this.observables.Value.Count - 1; i >= 0; i--)
            {
                this.Remove(this.observables.Value[i]);
            }
        }

        private static void HandleEvent(object sender, EventArgs args)
        {
            Console.WriteLine("Something happened to " + sender);
        }
    }
}

回答by Imran Rizvi

I did't want to change my source code to add additional observer , so I have written following simple example:

我不想更改我的源代码以添加额外的观察者,所以我编写了以下简单示例:

//EVENT DRIVEN OBSERVER PATTERN
public class Publisher
{
    public Publisher()
    {
        var observable = new Observable();
        observable.PublishData("Hello World!");
    }
}

//Server will send data to this class's PublishData method
public class Observable
{
    public event Receive OnReceive;

    public void PublishData(string data)
    {
        //Add all the observer below
        //1st observer
        IObserver iObserver = new Observer1();
        this.OnReceive += iObserver.ReceiveData;
        //2nd observer
        IObserver iObserver2 = new Observer2();
        this.OnReceive += iObserver2.ReceiveData;

        //publish data 
        var handler = OnReceive;
        if (handler != null)
        {
            handler(data);
        }
    }
}

public interface IObserver
{
    void ReceiveData(string data);
}

//Observer example
public class Observer1 : IObserver
{
    public void ReceiveData(string data)
    {
        //sample observers does nothing with data :)
    }
}

public class Observer2 : IObserver
{
    public void ReceiveData(string data)
    {
        //sample observers does nothing with data :)
    }
}

回答by Narottam Goyal

    /**********************Simple Example ***********************/    

class Program
        {
            static void Main(string[] args)
            {
                Parent p = new Parent();
            }
        }

        ////////////////////////////////////////////

        public delegate void DelegateName(string data);

        class Child
        {
            public event DelegateName delegateName;

            public void call()
            {
                delegateName("Narottam");
            }
        }

        ///////////////////////////////////////////

        class Parent
        {
            public Parent()
            {
                Child c = new Child();
                c.delegateName += new DelegateName(print);
                //or like this
                //c.delegateName += print;
                c.call();
            }

            public void print(string name)
            {
                Console.WriteLine("yes we got the name : " + name);
            }
        }

回答by Elena K

Something like this:

像这样的东西:

// interface implementation publisher
public delegate void eiSubjectEventHandler(eiSubject subject);

public interface eiSubject
{
    event eiSubjectEventHandler OnUpdate;

    void GenereteEventUpdate();

}

// class implementation publisher
class ecSubject : eiSubject
{
    private event eiSubjectEventHandler _OnUpdate = null;
    public event eiSubjectEventHandler OnUpdate
    {
        add
        {
            lock (this)
            {
                _OnUpdate -= value;
                _OnUpdate += value;
            }
        }
        remove { lock (this) { _OnUpdate -= value; } }
    }

    public void GenereteEventUpdate()
    {
        eiSubjectEventHandler handler = _OnUpdate;

        if (handler != null)
        {
            handler(this);
        }
    }

}

// interface implementation subscriber
public interface eiObserver
{
    void DoOnUpdate(eiSubject subject);

}

// class implementation subscriber
class ecObserver : eiObserver
{
    public virtual void DoOnUpdate(eiSubject subject)
    {
    }
}

. observer pattern C# with event. link to the repository

. 带有事件的观察者模式 C#链接到存储库

回答by Anestis Kivranoglou

Applying the Observer Patternwith delegates and events in c#is named "Event Pattern"according to MSDNwhich is a slight variation.

根据MSDN,在c# 中使用委托和事件应用观察者模式被命名为“事件模式”,这是一个轻微的变化。

In this Article you will find well structured examples of how to apply the pattern in c# both the classic way and using delegates and events.

在本文中,您将找到结构良好的示例,说明如何以经典方式以及使用委托和事件在 c# 中应用该模式。

Exploring the Observer Design Pattern

探索观察者设计模式

public class Stock
{

    //declare a delegate for the event
    public delegate void AskPriceChangedHandler(object sender,
          AskPriceChangedEventArgs e);
    //declare the event using the delegate
    public event AskPriceChangedHandler AskPriceChanged;

    //instance variable for ask price
    object _askPrice;

    //property for ask price
    public object AskPrice
    {

        set
        {
            //set the instance variable
            _askPrice = value;

            //fire the event
            OnAskPriceChanged();
        }

    }//AskPrice property

    //method to fire event delegate with proper name
    protected void OnAskPriceChanged()
    {

        AskPriceChanged(this, new AskPriceChangedEventArgs(_askPrice));

    }//AskPriceChanged

}//Stock class

//specialized event class for the askpricechanged event
public class AskPriceChangedEventArgs : EventArgs
{

    //instance variable to store the ask price
    private object _askPrice;

    //constructor that sets askprice
    public AskPriceChangedEventArgs(object askPrice) { _askPrice = askPrice; }

    //public property for the ask price
    public object AskPrice { get { return _askPrice; } }

}//AskPriceChangedEventArgs

回答by JerryGoyal

In this model, you have publishers who will do some logic and publish an "event."
Publishers will then send out their event only to subscribers who have subscribed to receive the specific event.

在此模型中,您的发布者将执行一些逻辑并发布“事件”。
然后,发布者将仅将其事件发送给已订阅接收特定事件的订阅者。

In C#, any object can publish a set of events to which other applications can subscribe.
When the publishing class raises an event, all the subscribed applications are notified.
The following figure shows this mechanism.

在 C# 中,任何对象都可以发布一组其他应用程序可以订阅的事件。
当发布类引发事件时,会通知所有订阅的应用程序。
下图显示了这种机制。

enter image description here

在此处输入图片说明

Simplest Example possible on Events and Delegates in C#:

C# 中事件和委托的最简单示例:

code is self explanatory, Also I've added the comments to clear out the code.

代码是不言自明的,我还添加了注释以清除代码。

  using System;

public class Publisher //main publisher class which will invoke methods of all subscriber classes
{
    public delegate void TickHandler(Publisher m, EventArgs e); //declaring a delegate
    public TickHandler Tick;     //creating an object of delegate
    public EventArgs e = null;   //set 2nd paramter empty
    public void Start()     //starting point of thread
    {
        while (true)
        {
            System.Threading.Thread.Sleep(300);
            if (Tick != null)   //check if delegate object points to any listener classes method
            {
                Tick(this, e);  //if it points i.e. not null then invoke that method!
            }
        }
    }
}

public class Subscriber1                //1st subscriber class
{
    public void Subscribe(Publisher m)  //get the object of pubisher class
    {
        m.Tick += HeardIt;              //attach listener class method to publisher class delegate object
    }
    private void HeardIt(Publisher m, EventArgs e)   //subscriber class method
    {
        System.Console.WriteLine("Heard It by Listener");
    }

}
public class Subscriber2                   //2nd subscriber class
{
    public void Subscribe2(Publisher m)    //get the object of pubisher class
    {
        m.Tick += HeardIt;               //attach listener class method to publisher class delegate object
    }
    private void HeardIt(Publisher m, EventArgs e)   //subscriber class method
    {
        System.Console.WriteLine("Heard It by Listener2");
    }

}

class Test
{
    static void Main()
    {
        Publisher m = new Publisher();      //create an object of publisher class which will later be passed on subscriber classes
        Subscriber1 l = new Subscriber1();  //create object of 1st subscriber class
        Subscriber2 l2 = new Subscriber2(); //create object of 2nd subscriber class
        l.Subscribe(m);     //we pass object of publisher class to access delegate of publisher class
        l2.Subscribe2(m);   //we pass object of publisher class to access delegate of publisher class

        m.Start();          //starting point of publisher class
    }
}

Output:

输出:

Heard It by Listener

听者所闻

Heard It by Listener2

由 Listener2 听到

Heard It by Listener

听者所闻

Heard It by Listener2

由 Listener2 听到

Heard It by Listener . . . (infinite times)

听者所闻。. . (无限次)