带代理的C#observer/observable的超简单示例

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)

  • 为了节省几行并避免空检查,请按如下方式初始化您的事件:http://stackoverflow.com/questions/340610/create-empty-c-event-handlers-automatically/340618#340618 (17认同)
  • @DanPuzey:你可以在课堂上,但同样你可以确保你*不*那样做 - 而*其他*代码不能这样做,因为它只能订阅和取消订阅.如果你确保在你的课程中没有故意将它设置为空,那么可以避免空检查. (4认同)
  • @JonSkeet:当然,我忘了你不能在课外做那件事.道歉! (2认同)
  • 我想你可以用'SomethingHappened?.Invoke(this,EventArgs.Empty)替换DoSomething中的所有东西;` (2认同)

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)

注意:

  • 这违反了一条规则,因为我没有将观察者从观察者中解开,这对于这个简单的例子来说可能已经足够好了,但要确保你不要让观察者像你那样悬挂你的事件.处理这个的方法是使ObserverClass IDisposable,并让.Dispose方法与构造函数中的代码相反
  • 没有执行错误检查,至少应该在ObserverClass的构造函数中进行空检查


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听到它

听众听说...(无限次)


Jes*_*cer 6

我把上面几个很好的例子(谢谢你一直感谢Skeet先生Karlsen先生)包括几个不同的Observable并利用一个接口在Observer中跟踪它们并允许Obse​​rver通过内部列表"观察"任意数量的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)


Ane*_*lou 5

根据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)