带有委托的 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
Super-simple example of C# observer/observable with delegates
提问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 DoSomething
safely to handle cases where SomethingHappened
has 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)
{
}
}
回答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# 中,任何对象都可以发布一组其他应用程序可以订阅的事件。
当发布类引发事件时,会通知所有订阅的应用程序。
下图显示了这种机制。
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)
听者所闻。. . (无限次)