2010-12-03 13 views
12

मेरे पास तीन ऑब्जेक्ट्स हैं ऑब्जेक्ट ए में ऑब्जेक्टबी है, ऑब्जेक्टबी में ऑब्जेक्टसी है। जब ObjectC एक घटना मैं ObjectA इसके बारे में पता करने की जरूरत आग, तो यह मैं क्या किया है है ...घटनाओं को बुलबुला करने का पसंदीदा तरीका क्या है?

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

इस इस संभाल करने के लिए उचित तरीका है, या वहाँ एक बेहतर तरीका है? मैं ऑब्जेक्ट को ऑब्जेक्टसी के बारे में नहीं जानना चाहता, केवल इतना ही कि उसने एक कार्यक्रम उठाया।

+1

यह बात करने का एक प्रभावी तरीका है। – jvanrhyn

उत्तर

16

एक और दृष्टिकोण, है यह/निकालें जोड़ने का उपयोग कर रैप करने के लिए:

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

ऐसा लगता है कि यह कुछ समय बचा सकता है अगर वहां बुलबुले के लिए घटनाओं का एक समूह है। धन्यवाद। – Tester101

3

यही तरीका है कि मैं इसे करता हूं। लेकिन मैं इस के लिए अपने गोलीबारी तंत्र को बदलने की सलाह देते हैं यह थ्रेड सुरक्षित

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

यह नाकाम रहने से यह होता रहता है तो EventFired अशक्त जांच और फायरिंग के बीच अशक्त हो जाता है बनाने के लिए होगा।

यह भी आपके ईवेंट प्रतिनिधियों के लिए EventHandler pattern का पालन करने के लिए मानक का कुछ हद तक है।

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

मैं threadsafe पैटर्न के बारे में गलत था, यहाँ पूर्ण threadsafe घटना पैटर्न

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

क्यों नहीं होता ओपी रास्ता धागा सुरक्षित हो? –

+0

@ माइक चेल जैसा कि मैंने पोस्ट में कहा था, अगर घटना को शून्य जांच के बीच सदस्यता रद्द कर दिया गया है और वास्तविक फायरिंग एक अपवाद (NullRefrence मुझे लगता है) फेंक दिया जाएगा। ईवेंट को एक अलग चर पर असाइन करके, ईवेंट को अभी भी अंतिम बार आग लग जाएगी यदि यह इस फ़ंक्शन के बीच में सदस्यता समाप्त हो गई थी। –

+0

सामान्य हस्ताक्षर 'सुरक्षित आभासी शून्य OnMyEvent (MyEventArgs ई) 'नहीं है? – Greg

1

जैसा कि अन्य उत्तरों ने कहा है, यह वही तरीका है।

लेकिन आप इससे आगे जा सकते हैं !!! मैंने अभी इस पर एक अच्छी डेटा संरचना लागू की है, और यह आपको इस पर एक स्पिन देना पसंद है।

स्वचालित ईवेंट बुलबुल करना अच्छा लगेगा? आप प्रतिबिंब का उपयोग कर इसे लागू कर सकते हैं। मेरा तरीका एक इंटरफ़ेस/बेस क्लास को परिभाषित करना है जो एक ईवेंट (या घटनाओं का एक सेट) घोषित करता है। फिर, बेस क्लास का पैरामीटर रहित कन्स्ट्रक्टर अन्य गुणों/फ़ील्ड को फिर से सक्रिय करेगा, और ईवेंट प्रचार के लिए स्वचालित रूप से सदस्यों की घटनाओं को पंजीकृत करेगा।

डिज़ाइन पर कुछ प्रतिबंध हैं, लेकिन यदि आपके पास गहरी संरचना और/या कई (संरचित) घटनाएं हैं, तो कोड के किसी अतिरिक्त लाइन के बिना सबकुछ सेटअप करना अच्छा लगेगा।

एक प्रारंभिक आधार वर्ग हो सकता है:

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; 

} 
बेशक

, के रूप में पहले से ही सुझाव दिया, घटना प्रतिनिधि प्रतिनिधि (वस्तु प्रेषक, EventArgs args) का पालन (मैं स्पष्टता के लिए एक सरल घटना का उपयोग किया है) । स्वाभाविक रूप से, कि तुम कक्षाएं एक, बी और सी सीधे BaseObject से निकला है निहित है।

ध्यान दें कि किसी भी तर्क संरचित घटनाओं बाध्य करने के लिए लागू किया जा सकता (आप नेस्टेड घटना पंजीकरण नाम और/या अन्य परिलक्षित गुणों का उपयोग करके किया जा सकता है।

संबंधित मुद्दे