सी #: विरासत में मिली घटना को उठाना


144

मेरा एक बेस क्लास है जिसमें निम्नलिखित घटनाएँ हैं:

public event EventHandler Loading;
public event EventHandler Finished;

इस बेस क्लास से विरासत में मिली कक्षा में मैं इस घटना को उठाने की कोशिश करता हूँ:

this.Loading(this, new EventHandler()); // All we care about is which object is loading.

मुझे निम्न त्रुटि प्राप्त हुई:

घटना 'BaseClass.Loading' केवल + = या - = (BaseClass ') के बाईं ओर दिखाई दे सकती है

मैं यह मान रहा हूं कि मैं इन घटनाओं को अन्य विरासत वाले सदस्यों की तरह एक्सेस नहीं कर सकता हूं?


इस सवाल का जवाब फ्रेडरिक घीसेल्स ने पहले ही दे दिया था । Microsoft डॉक्स पर समान अभ्यास की सिफारिश की जाती है: व्युत्पन्न वर्गों में आधार वर्ग की घटनाओं को कैसे बढ़ाया जाए (सी # प्रोग्रामिंग गाइड) एक आधिकारिक "सी # प्रोग्रामिंग गाइड" के रूप में
एलियाहु आरोन

जवाबों:


160

आपको क्या करना है, यह है:

अपने आधार वर्ग में (जहाँ आपने घटनाओं को घोषित किया है), संरक्षित तरीके बनाएँ, जिनका उपयोग घटनाओं को बढ़ाने के लिए किया जा सकता है:

public class MyClass
{
   public event EventHandler Loading;
   public event EventHandler Finished;

   protected virtual void OnLoading(EventArgs e)
   {
       EventHandler handler = Loading;
       if( handler != null )
       {
           handler(this, e);
       }
   }

   protected virtual void OnFinished(EventArgs e)
   {
       EventHandler handler = Finished;
       if( handler != null )
       {
           handler(this, e);
       }
   }
}

(ध्यान दें कि आपको शायद उन तरीकों को बदलना चाहिए, ताकि आपको यह पता चल सके कि आपको इवेंटहैंडलर को आमंत्रित करना है या नहीं)।

फिर, इस बेस क्लास से विरासत में मिलने वाली कक्षाओं में, आप घटनाओं को बढ़ाने के लिए ऑनफिनिश या ऑनलोडिंग विधियों को कॉल कर सकते हैं:

public AnotherClass : MyClass
{
    public void DoSomeStuff()
    {
        ...
        OnLoading(EventArgs.Empty);
        ...
        OnFinished(EventArgs.Empty);
    }
}

5
उन तरीकों को वर्चुअल संरक्षित किया जाना चाहिए जब तक कि कोई कारण न हो अन्यथा।
मैक्स शिमलिंग

6
यह आभासी क्यों होना चाहिए? मैं इसे आभासी घोषित करूँगा अगर मैं चाहता था कि घटना को जिस तरह से उठाया जाना चाहिए, उसे बदलने के लिए मैं चाहता था, लेकिन ज्यादातर समय, मुझे ऐसा करने का कोई कारण नहीं दिखता ...
फ्रेडरिक घीसेल्स

4
आधिकारिक दिशानिर्देश: msdn.microsoft.com/en-us/library/w369ty8x(VS.80).aspx
meandmycode

5
विधि को आभासी बनाने के बारे में, ताकि इनहेरिटर्स इवेंट इंवोकेशन व्यवहार को ओवरराइड कर सकें: आप कितनी बार ऐसी स्थिति में आए हैं जहां यह आवश्यक था? कि बगल में; ओवरराइड विधि में, आप ईवेंट को नहीं बढ़ा सकते हैं, क्योंकि आपको टीएस द्वारा उल्लिखित एक ही त्रुटि मिलेगी।
फ्रेडरिक घीसेल्स

2
@ वीयरैक्स मैं इसका अनुसरण करता हूं क्योंकि तर्क ध्वनि है, इस पर निर्भर करता है कि कोड के पुन: प्रयोज्य और एक्स्टेंसिबल होने की उम्मीद है, मैंने इसे वापस करने के लिए आधिकारिक दिशा-निर्देश प्रदान किए हैं .. लिखने के समय आप .NET वेराक्स के लिए भी बहुत नए लगते हैं इसलिए यह थोड़ा हैरान करने वाला है कि आपने मेरे 7 साल के अनुभव से असहमत होने के लिए इसे खोद लिया
meandmycode

123

आप केवल घोषित वर्ग में एक घटना का उपयोग कर सकते हैं, क्योंकि .NET उन दृश्यों के पीछे निजी उदाहरण चर बनाता है जो वास्तव में प्रतिनिधि को रखते हैं। यह कर रहा हूं..

public event EventHandler MyPropertyChanged;

वास्तव में यह कर रहा है;

private EventHandler myPropertyChangedDelegate;

public event EventHandler MyPropertyChanged
{
    add { myPropertyChangedDelegate += value; }
    remove { myPropertyChangedDelegate -= value; }
}

और यह कर ...

MyPropertyChanged(this, EventArgs.Empty);

वास्तव में यह है ...

myPropertyChangedDelegate(this, EventArgs.Empty);

तो आप (स्पष्ट रूप से) केवल घोषित वर्ग के भीतर से निजी प्रतिनिधि उदाहरण चर का उपयोग कर सकते हैं।

अधिवेशन को घोषित वर्ग में कुछ इस तरह प्रदान करना है।

protected virtual void OnMyPropertyChanged(EventArgs e)
{
    EventHandler invoker = MyPropertyChanged;

    if(invoker != null) invoker(this, e);
}

फिर आप OnMyPropertyChanged(EventArgs.Empty)उस वर्ग में कहीं से भी या घटना को लागू करने के लिए विरासत उत्तराधिकार के नीचे से कॉल कर सकते हैं ।


मेरे पास इसे लागू करने के कुछ मुद्दे थे ... stackoverflow.com/q/10593632/328397
goodguys_activate

मैं इस उत्तर को पसंद करता हूं क्योंकि यह बताता है कि आपको दृष्टिकोण के बजाय दृष्टिकोण का उपयोग क्यों करना है। अच्छा काम।
चरवाहे

8

मैं यह मान रहा हूं कि मैं इन घटनाओं को अन्य विरासत वाले सदस्यों की तरह एक्सेस नहीं कर सकता हूं?

यकीनन। विरासत में मिली कक्षाओं को बढ़ाने के लिए यह एक संरक्षित कार्य प्रदान करने OnXyzया RaiseXyzबेस क्लास में प्रत्येक घटना के लिए प्रथागत है । उदाहरण के लिए:

public event EventHandler Loading;

protected virtual void OnLoading() {
    EventHandler handler = Loading;
    if (handler != null)
        handler(this, EventArgs.Empty);
}

विरासत में मिला वर्ग:

OnLoading();

0

आप इस तरह से कोशिश कर सकते हैं, यह मेरे लिए काम करता है:

public delegate void MyEventHaldler(object sender, EventArgs e);

public class B
{
    public virtual event MyEventHaldler MyEvent;
    protected override void OnChanged(EventArgs e)
    {
        if (MyEvent != null)
            MyEvent(this, e);
    }
}

public class D : B
{
    public override event MyEventHaldler MyEvent;
    protected override void OnChanged(EventArgs e)
    {
        if (MyEvent != null)
            MyEvent(this, e);
    }
}

2
ध्यान दें कि यह लेख आभासी घटनाओं की घोषणा करने और उन्हें ओवरराइड करने के खिलाफ चेतावनी देता है क्योंकि यह दावा करता है कि कंपाइलर इसे सही तरीके से नहीं संभालता है: msdn.microsoft.com/en-us/library/hy3sefw3.aspx
सार्वजनिक वायरलेस

0

एक पुराने धागे को फिर से जीवित करने के लिए नहीं, लेकिन अगर कोई देख रहा है कि मैंने क्या किया था

protected EventHandler myPropertyChangedDelegate;

public event EventHandler MyPropertyChanged
{
    add { myPropertyChangedDelegate += value; }
    remove { myPropertyChangedDelegate -= value; }
}

यह आपको एक व्युत्पन्न वर्ग में घटना की अनुमति देता है ताकि आप इसे + = वाक्यविन्यास रखते हुए विधि को लपेटने की आवश्यकता के बिना इसे लागू कर सकें। मुझे लगता है कि आप अभी भी रैपिंग विधियों के साथ कर सकते हैं यदि आपने किया

public event EventHandler MyPropertyChanged
{
   add { AddDelegate(value); }
   remove { RemoveDelegate(value); }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.