2010-12-03 18 views
12

Ich habe drei Objekte ObjectA hat ein ObjectB, ObjectB hat ein ObjectC. Wenn ObjectC feuert ein Ereignis ich ObjectA muß darüber Bescheid wissen, so ist dies, was ich habe ... getanWas ist der bevorzugte Weg, um Ereignisse zu blasen?

public delegate void EventFiredEventHandler(); 

public class ObjectA 
{ 
    ObjectB objB; 

    public ObjectA() 
    { 
     objB = new ObjectB(); 
     objB.EventFired += new EventFiredEventHandler(objB_EventFired); 
    } 

    private void objB_EventFired() 
    { 
     //Handle the event. 
    } 
} 

public class ObjectB 
{ 
    ObjectC objC; 

    public ObjectB() 
    { 
     objC = new ObjectC(); 
     objC.EventFired += new EventFiredEventHandler(objC_EventFired); 
     objC.FireEvent(); 
    } 

    public event EventFiredEventHandler EventFired; 
    protected void OnEventFired() 
    { 
     if(EventFired != null) 
     { 
      EventFired(); 
     } 
    } 

    private void objC_EventFired() 
    { 
      //objC fired an event, bubble it up. 
     OnEventFired(); 
    } 
} 

public class ObjectC 
{ 
    public ObjectC(){} 

    public void FireEvent() 
    { 
     OnEventFired(); 
    } 

    public event EventFiredEventHandler EventFired; 
    protected void OnEventFired() 
    { 
     if(EventFired != null) 
     { 
      EventFired(); 
     } 
    } 
} 

Ist dies der richtige Weg, dies zu umgehen, oder gibt es einen besseren Weg? Ich möchte nicht, dass ObjectA überhaupt von ObjectC weiß, sondern nur, dass es ein Ereignis ausgelöst hat.

+1

Dies ist ein effektiver Weg, um es zu tun. – jvanrhyn

Antwort

16

Ein weiterer Ansatz, wickeln wird es unter Verwendung hinzufügen/entfernen:

public class ObjectB 
{ 
    ObjectC objC; 

    public ObjectB() 
    { 
     objC = new ObjectC(); 
    } 

    public event EventFiredEventHandler EventFired 
    { 
     add { this.objC.EventFired += value; } 
     remove { this.objC.EventFired -= value; } 
    } 
} 
+0

Dies scheint so zu sein, als könnte es Zeit sparen, wenn es eine Menge an Ereignissen geben würde. Vielen Dank. – Tester101

3

So mache ich es. jedoch würde ich empfehlen, Ihren Zündmechanismus Um dies zu ändern, um sie sicher

protected void OnEventFired() 
{ 
    var tmpEvent = EventFired; 
    if(tmpEvent != null) 
    { 
     tmpEvent(); 
    } 
} 

Dies hält Thread zu machen Fehlschlagen, wenn EventFired zwischen der NULL-Prüfung und dem Feuer null wird.

Auch ist es ein Standard, die EventHandler pattern für Ihre Event-Delegierten zu folgen.

protected virtual void OnEventFired(EventArgs e) 
{ 
    var tmpEvent = EventFired; 
    if(tmpEvent != null) 
    { 
     tmpEvent(this, EventArgs.e); 
    } 
} 

Ich war falsch über das Thread-Muster, hier ist der volle THREADEreignisMuster

/// <summary> 
/// Delegate backing the SomeEvent event. 
/// </summary> 
SomeEventHandler someEvent; 

/// <summary> 
/// Lock for SomeEvent delegate access. 
/// </summary> 
readonly object someEventLock = new object(); 

/// <summary> 
/// Description for the event 
/// </summary> 
public event SomeEventHandler SomeEvent 
{ 
    add 
    { 
     lock (someEventLock) 
     { 
      someEvent += value; 
     } 
    } 
    remove 
    { 
     lock (someEventLock) 
     { 
      someEvent -= value; 
     } 
    } 
} 

/// <summary> 
/// Raises the SomeEvent event 
/// </summary> 
protected virtual OnSomeEvent(EventArgs e) 
{ 
    SomeEventHandler handler; 
    lock (someEventLock) 
    { 
     handler = someEvent; 
    } 
    if (handler != null) 
    { 
     handler (this, e); 
    } 
} 
+0

Warum sollte nicht die OP-Art ist threadsicher? –

+0

@Mike Cheel Wie ich in der Post sagte, wenn das Ereignis zwischen dem Null-Check und dem tatsächlichen Feuern abgemeldet ist, wird eine Exception (NullRefrence, denke ich) geworfen. Wenn Sie das Ereignis einer separaten Variablen zuweisen, wird das Ereignis immer noch das letzte Mal ausgelöst, wenn es in der Mitte dieser Funktion abgemeldet wurde. –

+0

Ist nicht die übliche Signatur 'protected virtual void OnMyEvent (MyEventArgs e)'? – Greg

1

Wie andere Antworten gesagt haben, ist dies der Weg, es zu tun.

Aber Sie können darüber hinaus gehen !!! Ich habe gerade eine gute Datenstruktur implementiert, und es ist wie eine Art Spin.

Wäre es schön, wenn ein automatisches Ereignis sprudelt? Sie könnten es mit Reflection implementieren. Mein Weg ist es, eine Interface/Base-Klasse zu definieren, die ein Event (oder eine Menge von Events) deklariert. Dann wird der parameterlose Konstruktor einer Basisklasse andere Eigenschaften/Felder iterieren und automatisch die Member-Ereignisse für die Ereignisausbreitung registrieren.

Es gibt einige Einschränkungen beim Design, aber wenn Sie eine tiefe Struktur und/oder viele (strukturierte) Ereignisse haben, könnte es nett sein, alles ohne zusätzliche Codezeile einzurichten.

Eine erste Basisklasse sein könnte:

class BaseObject { 
    public BaseObject() { 
     FieldInfo[] fInfos = this.GetType().GetFields(...); 

     foreach (FieldInfo fInfo in fInfos) { 
      object fInfoValue = fInfo.GetValue(this, null); 
      if (fInfoValue is BaseObject) { 
       BaseObject bMemberObject = (BaseObject)fInfoValue; 

       bMemberObject.MyEvent += new EventHandler(delegate() { 
        if (this.MyEvent != null) 
         MyEvent(); 
       }); 
      } 
    } 

    public event MyEvent = null; 

} 

Natürlich, wie bereits angedeutet, folgen Sie dem Ereignisdelegaten delegieren (object sender, EventArgs args) (Ich habe eine einfachere Ereignis für Klarheit verwendet) . Natürlich ist implizit, dass Sie Klassen A, B und C direkt von Baseobject ableitet.

Beachten Sie, dass jede Logik strukturierte Ereignisse zu binden umgesetzt werden könnten (Sie die verschachtelte Event-Registrierung unter Verwendung des Namens sein könnte und/oder andere Eigenschaften reflektiert.

Verwandte Themen