Den*_*gan 131 c# events delegates observer-pattern
我最近开始深入研究C#,但我不能通过我的生活弄清楚委托在语言中实现观察者/可观察模式时的工作方式.
有人能给我一个超级简单的例子说明它是如何完成的吗?我用谷歌搜索了这个,但我发现的所有例子都是特定于问题或过于"臃肿".
Jon*_*eet 216
观察者模式通常用事件实现.
这是一个例子:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
有关更多详细信息,请参阅链接的文章.
请注意,上面的示例使用C#6 空条件运算符来DoSomething安全地实现处理SomethingHappened尚未订阅的情况,因此为null.如果您使用的是旧版本的C#,则需要以下代码:
public void DoSomething()
{
var handler = SomethingHappened;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
Run Code Online (Sandbox Code Playgroud)
ang*_*son 16
这是一个简单的例子:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
注意:
Jer*_*yal 15
在此模型中,您有发布者将执行某些逻辑并发布"事件".
然后,发布者将仅向已订阅接收特定事件的订阅者发送其活动.
在C#中,任何对象都可以发布其他应用程序可以订阅的一组事件.
当发布类引发事件时,将通知所有已订阅的应用程序.
下图显示了此机制.
C#中事件和委托的最简单示例:
代码是自我解释的,我也添加了注释以清除代码.
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
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
听众听说
通过Listener2听到它
听众听说
通过Listener2听到它
听众听说...(无限次)
我把上面几个很好的例子(谢谢你一直感谢Skeet先生和Karlsen先生)包括几个不同的Observable并利用一个接口在Observer中跟踪它们并允许Observer通过内部列表"观察"任意数量的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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
根据MSDN,在c# 中使用委托和事件应用观察者模式被命名为“事件模式”,这是一个轻微的变化。
在本文中,您将找到结构良好的示例,说明如何以经典方式以及使用委托和事件在 c# 中应用该模式。
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
Run Code Online (Sandbox Code Playgroud)