2009-08-08 3 views
114

Ich habe vor kurzem angefangen, in C# zu graben, aber ich kann nicht nach meinem Leben herausfinden, wie Delegierte arbeiten, wenn sie das beobachtbare Muster in der Sprache implementieren.Super-einfaches Beispiel für C# -Observer/beobachtbar mit Delegierten

Könnte mir jemand ein super einfaches Beispiel geben, wie es gemacht wird? Ich habe googleed dies, aber alle Beispiele, die ich gefunden habe, waren entweder zu problemspezifisch oder zu "aufgebläht".

Antwort

188

Das Beobachtermuster wird normalerweise mit events implementiert.

Hier ist ein Beispiel:

using System; 

class Observable 
{ 
    public event EventHandler SomethingHappened; 

    public void DoSomething() 
    { 
     EventHandler handler = SomethingHappened; 
     if (handler != null) 
     { 
      handler(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(); 
    } 
} 

für viel mehr Detail die verlinkte Artikel.

+15

Um ein paar Zeilen zu sparen und den Null-Check zu vermeiden, initialisieren Sie Ihre Veranstaltung wie folgt: http://stackoverflow.com/questions/340610/create-empty-c-event-handlers-automatically/ 340618 # 340618 – Dinah

+1

@Dinah: Das vermeidet den Null-Check nicht. Sie können später noch 'SomethingHappened = null' setzen (eine praktische, wenn auch faule und nicht ideale Möglichkeit, alle Handler abzumelden), so dass die Nullprüfung immer notwendig ist. –

+3

@DanPuzey: Sie können innerhalb der Klasse, aber ebenso können Sie sicherstellen, dass Sie * nicht tun * - und * anderen * Code kann es nicht tun, da es nur abonnieren und abmelden kann. Wenn Sie sicherstellen, dass Sie ihn nie innerhalb Ihrer Klasse auf null setzen, ist es in Ordnung, die Nullprüfung zu vermeiden. –

16

Hier ist ein einfaches Beispiel:

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

Hinweis:

  • Diese eine Regel, dass verletzt ich, das ist vielleicht gut genug für dieses einfache Beispiel nicht die Beobachter aus dem beobachtbaren aushängen , aber stellen Sie sicher, dass Sie die Beobachter nicht davon abhalten, so von Ihren Ereignissen abzuhängen. Eine Möglichkeit, dies zu tun, wäre ObserverClass IDisposable zu machen, und die .Dispose-Methode das Gegenteil des Codes im Konstruktor
  • Keine Fehlerprüfung durchgeführt, sollte mindestens eine Null-Überprüfung im Konstruktor der durchgeführt werden ObserverClass
5

prüfen diese Einführung in Rx-Framework, die verwendet wunderbare IObserver-IObservable non-blocking asynchroner Programmiermodell introducing-rx-linq-to-events

+0

Eine gute Sache, wenn Sie Silverlight verwenden - leider nicht viel für den Rest von uns. Eine Schande. –

+0

Sie können es in .net clr konvertieren. Sehen Sie hier http://evain.net/blog/articles/2009/07/30/rebasing-system-reactive-to-the-net-clr – Ray

+0

Auch wird es ein Teil von .NET 4.0 sein (und nicht nur für Silverlight) – Ray

5

ich habe zusammen gebunden ein paar der großen Beispiele oben (danke wie immer zu Mr. Skeet und Mr. Karlsen) um ein paar verschiedene Observables einzuschließen und eine Schnittstelle zu verwenden, um t zu behalten Rack von ihnen in den Observer und erlaubt die Beobachter eine beliebige Anzahl von Observablen über eine interne Liste zu „beobachten“:

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

ich did't meine Quelle möchte Code ändern zusätzlichen Beobachter hinzuzufügen, so dass ich geschrieben habe folgende einfache Beispiel:

//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 :) 
    } 
} 
1
/**********************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); 
      } 
     } 
0

Etwas wie folgt aus:

// 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

4

Anwendung des Observer Pattern mit Delegierten und Veranstaltungen in C# ist "Ereignismuster" benannt nach MSDN, die eine leichte Variation ist.

In diesem Artikel finden Sie gut strukturierte Beispiele für die Anwendung des Musters in C# sowohl auf die klassische Weise als auch unter Verwendung von Delegaten und Ereignissen.

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 
12

In diesem Modell haben Sie Publisher, die eine gewisse Logik und veröffentlichen tun "Ereignis".
Publisher verschicken ihre Veranstaltung nur an Abonnenten, die sich für den Erhalt der spezifischen Veranstaltung angemeldet haben.

In C# kann jedes Objekt eine Reihe von Ereignissen veröffentlichen, die von anderen Anwendungen abonniert werden können.
Wenn die Veröffentlichungsklasse ein Ereignis auslöst, werden alle abonnierten Anwendungen benachrichtigt.
Die folgende Abbildung zeigt diesen Mechanismus.

enter image description here

einfachstes Beispiel möglich, auf Ereignisse und Delegaten in C#:

Code ist selbsterklärend, auch habe ich die Kommentare hinzugefügt, um den Code zu löschen.

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 
    } 
} 

Ausgang:

Gehört ihm durch Listener

Es wird von Listener2 Heard

Es wird von Zuhörer gehört

Gehört ihm durch Listener2

Es gehört von Hör mal zu er . . . (unendliche Zeiten)

+1

Das ist großartig, danke für das einfache und klare Beispiel. –

+1

Du hast meinen Tag gerettet :) Danke ... –

Verwandte Themen