2012-03-31 26 views
5

मैं एक सामान्य इवेंट बनाने के प्रयास कर रहा हूँ। मूल रूप से यह इस तरह दिखना चाहिए:EventHandlers और सहप्रसरण

namespace DelegateTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var lol = new SomeClass(); 
      lol.SomeEvent += handler; 
     } 

     static void handler(object sender, SomeDerivedClass e) 
     { 

     } 

    } 

    class SomeClass 
    { 

     public delegate void SomeEventDelegate<in T>(object sender, T data); 
     public event SomeEventDelegate<ISomeInterface> SomeEvent; 

    } 

    interface ISomeInterface 
    { 
    } 

    class SomeDerivedClass : ISomeInterface 
    { 
    } 
} 

मैं किसी भी प्रतिनिधि है जो दूसरा पैरामीटर से ली गई है पारित करने के लिए उपयोगकर्ता की अनुमति देना चाहते "ISomeInterface।"

"में" सही को निर्दिष्ट विपरीत विचरण,? इसका अर्थ यह है कि यदि एपीआई कुछ और सामान्य की उम्मीद कर रहा है, तो आप इसे और अधिक विशिष्ट (मेरे आधार "आईसोमइंटरफेस" में सामान्य हो सकते हैं, और मेरा "कुछ डीरियड क्लास" विशिष्ट होगा।) हालांकि, मुझे अपने कंपाइलर को बताया जा रहा है कि "विधि हैंडलर के लिए कोई अधिभार DelegateTest.SomeClass.SomeEventDelegate मेल खाता है।"

मुझे आश्चर्य है कि यह क्यों काम नहीं कर रहा है। अगर समस्याएं होती हैं तो क्या समस्याएं होती हैं? या क्या मैं इसके लिए काम करने के लिए कुछ याद कर रहा हूँ?

अग्रिम धन्यवाद!

+0

देखें http://stackoverflow.com/questions/129453/net-eventhandlers-generic-or-no –

+0

मुझे लगता है कि आपके पास एकाधिक प्रकारों को संभालने के लिए एक भी ईवेंट नहीं हो सकता है, आप केवल प्रतिनिधि ही हो सकते हैं। आप अपने हैंडलर को 'ISomeInterface' को स्वीकार करने के लिए बदलने के लिए क्या कर सकते हैं, और उसके बाद भेजे गए ऑब्जेक्ट के प्रकार की जांच करें। या इंटरफ़ेस का उपयोग करें। http://msdn.microsoft.com/en-us/library/dd469484.aspx – BrunoLM

उत्तर

6

"में", सही निर्दिष्ट करता है विपरीत विचरण?

हां।

इसका मतलब है कि अगर एपीआई कुछ और सामान्य की उम्मीद कर रहा है, तो आप इसे और अधिक विशिष्ट (मेरे आधार "आईसोमइंटरफेस" में सामान्य हो सकते हैं, और मेरा "कुछ डीरियड क्लास" विशिष्ट होगा)।

सं। प्रतिनिधि प्रतिनिधिमंडल एक प्रतिनिधि को पैरामीटर प्रकारों के साथ एक विधि का संदर्भ देने की अनुमति देता है जो प्रतिनिधि प्रकार से कम व्युत्पन्न होता है। उदाहरण के लिए, मान लीजिए ISomeInterface एक आधार इंटरफेस था:

interface ISomeBaseInterface 
{ 
} 

interface ISomeInterface : ISomeBaseInterface 
{ 
} 

और लगता है handler बजाय ISomeBaseInterface ले लिया SomeDerivedClass की:

static void handler(object sender, ISomeBaseInterface e) 

फिर new SomeClass().SomeEvent += handler काम करेगा।

यहाँ क्यों मूल कोड सुरक्षित टाइप नहीं कर रहा है: जब SomeClassSomeEvent को जन्म देती है, यह संभावित कुछ भी कि ISomeInterfacedata तर्क के रूप में लागू करता है पारित कर सकते हैं। उदाहरण के लिए, यह SomeDerivedClass का एक उदाहरण दे सकते हैं, लेकिन यह भी

class SomeOtherDerivedClass : ISomeInterface 
{ 
} 

का एक उदाहरण दे सकते हैं, तो आप घटना के साथ void handler(object sender, SomeDerivedClass e) रजिस्टर करने में सक्षम थे, कि हैंडलर हवा होगा SomeOtherDerivedClass साथ लागू किया जा रहा है, जो नहीं करता है ' टी काम नहीं

सारांश में, आप ईवेंट हैंडलर्स कि अधिक सामान्य घटना प्रकार की तुलना में, नहीं ईवेंट हैंडलर्स कि अधिक विशिष्ट हैं रजिस्टर कर सकते हैं।

अद्यतन: आप टिप्पणी की:

ठीक है, मैं वास्तव में सूची के माध्यम से पुनरावृति और प्रकार की जांच करना चाहते।तो अगर घटना के SomeOtherDerivedObject मान लीजिए प्रकार के एक डेटा वस्तु के साथ निकाल दिया जा रहा था, तो कार्यक्रम विधि की सूची जब तक यह एक है कि हस्ताक्षर (वस्तु, SomeOtherDerivedObject) से मेल खाता है पता चलता है कि घटना की सदस्यता ली है के माध्यम से पुनरावृति होगी। इसलिए घटना का उपयोग केवल स्टोर करने के लिए किया जाएगा, वास्तव में प्रतिनिधियों को नहीं बुलाया जाएगा।

मुझे नहीं लगता कि सी # आप एक event कि मनमाने ढंग से प्रतिनिधि प्रकार के साथ काम करता है की घोषणा कर सकते हैं।

class SomeClass 
{ 
    private Delegate handlers; 

    public delegate void SomeEventDelegate<in T>(object sender, T data); 

    public void AddSomeEventHandler<T>(SomeEventDelegate<T> handler) 
    { 
     this.handlers = Delegate.Combine(this.handlers, handler); 
    } 

    protected void OnSomeEvent<T>(T data) 
    { 
     if (this.handlers != null) 
     { 
      foreach (SomeEventDelegate<T> handler in 
       this.handlers.GetInvocationList().OfType<SomeEventDelegate<T>>()) 
      { 
       handler(this, data); 
      } 
     } 
    } 
} 
+0

धन्यवाद। क्या यह दूसरी तरफ काम करने के लिए कोई रास्ता है? मैं वर्तमान में जावा-जैसे दृष्टिकोण (इंटरफेस + एडलिस्टर) का उपयोग कर रहा हूं। – haiyyu

+1

यदि आप पूरी तरह से निश्चित हैं कि 'SomeDerivedClass' के केवल कुछ पास उदाहरणों के साथ 'SomeClass'' डेटा' तर्क के रूप में, तो आप एक स्पष्ट कलाकार जोड़ सकते हैं : 'lol.SomeEvent + = (प्रेषक, ई) => हैंडलर (प्रेषक, (कुछDerivedClass) ई)'। लेकिन फिर आप 'SomeEvent' को' SomeEventDelegate 'के रूप में भी घोषित कर सकते हैं। –

+0

ठीक है, मैं वास्तव में सूची के माध्यम से पुन: प्रयास करना चाहता हूं और प्रकारों की जांच करना चाहता हूं। तो यदि घटना को डेटा ऑब्जेक्ट के साथ निकाल दिया गया था तो आइए कुछ अन्य डाइरेवॉइड ऑब्जेक्ट कहें, तो प्रोग्राम ईवेंट की सदस्यता लेने वाली विधियों की सूची के माध्यम से फिर से शुरू होगा जब तक यह हस्ताक्षर (ऑब्जेक्ट, SomeOtherDerivedObject) से मेल खाता है। इसलिए घटना का उपयोग केवल स्टोर करने के लिए किया जाएगा, वास्तव में प्रतिनिधियों को नहीं बुलाया जाएगा। मुझे उम्मीद है कि समझ में आया था। – haiyyu

2

प्रतिनिधि contravariance साथ एक प्रमुख झुंझलाहट है कि जब प्रकार का एक प्रतिनिधि उदाहरण है: यहाँ कैसे आप तरीकों कि ईवेंट हैंडलर्स जोड़ने के लिखने और उन्हें आह्वान कर सकते हैं है Action<Fruit>Action<Banana> की अपेक्षा रखने वाले दिनचर्या को पारित किया जा सकता है, जो दो प्रतिनिधि जो गिनती के लिए Action<Fruit> और Action<Banana> असफल हो जाएंगे, भले ही दोनों प्रतिनिधियों के पास "संकलन-समय" प्रकार Action<Banana> हो। इस के आसपास पाने के लिए, मैं निम्नलिखित की तरह एक विधि का उपयोग कर सुझाव है:

static T As<T>(this Delegate del) where T : class 
    { 
     if (del == null || del.GetType() == typeof(T)) return (T)(Object)del; 
     Delegate[] invList = ((Delegate)(Object)del).GetInvocationList(); 
     for (int i = 0; i < invList.Length; i++) 
      if (invList[i].GetType() != typeof(T)) 
       invList[i] = Delegate.CreateDelegate(typeof(T), invList[i].Target, invList[i].Method); 
     return (T)(Object)Delegate.Combine(invList); 
    } 

एक प्रतिनिधि और एक प्रतिनिधि प्रकार को देखते हुए पारित कर दिया-में प्रतिनिधि के प्रकार के ठीक निर्दिष्ट प्रकार से मेल खाता है या नहीं, इस विधि की जाँच करेगा; यदि ऐसा नहीं होता है, लेकिन मूल प्रतिनिधि में विधि (ओं) में निर्दिष्ट प्रकार के लिए उचित हस्ताक्षर हैं, तो आवश्यक विशेषताओं के साथ एक नया प्रतिनिधि बनाया जाएगा। ध्यान दें कि यदि दो अलग अवसरों पर इस समारोह प्रतिनिधियों जो उचित प्रकार की नहीं हैं, लेकिन जो एक दूसरे के बराबर की तुलना पारित हो जाता है, प्रतिनिधियों इस विधि द्वारा वापस भी एक दूसरे के बराबर की तुलना करेंगे। इस प्रकार, यदि एक एक घटना है जो प्रकार Action<string> के एक प्रतिनिधि को स्वीकार करना है है, एक उपरोक्त विधि जैसे कन्वर्ट करने के लिए इस्तेमाल कर सकते हैं एक पारित कर दिया-इन Action<object> एक "वास्तविक" Action<string> में जोड़ने या घटना से निकालने से पहले।

static void AppendTo<T>(this Delegate newDel, ref T baseDel) where T : class 
    { 
     newDel = (Delegate)(Object)newDel.As<T>(); 
     T oldBaseDel, newBaseDel; 
     do 
     { 
      oldBaseDel = baseDel; 
      newBaseDel = (T)(Object)Delegate.Combine((Delegate)(object)oldBaseDel, newDel); 
     } while (System.Threading.Interlocked.CompareExchange(ref baseDel, newBaseDel, oldBaseDel) != oldBaseDel); 
    } 

    static void SubtractFrom<T>(this Delegate newDel, ref T baseDel) where T : class 
    { 
     newDel = (Delegate)(Object)newDel.As<T>(); 
     T oldBaseDel, newBaseDel; 
     do 
     { 
      oldBaseDel = baseDel; 
      newBaseDel = (T)(Object)Delegate.Remove((Delegate)(object)oldBaseDel, newDel); 
     } while (System.Threading.Interlocked.CompareExchange(ref baseDel, newBaseDel, oldBaseDel) != oldBaseDel); 
    } 

इन विधियों करेंगे:

जोड़ने जाएगा या उचित प्रतिनिधि प्रकार के एक क्षेत्र से एक पारित कर दिया-में प्रतिनिधि को घटाकर, प्रकार निष्कर्ष और Intellisense व्यवहार करता है, तो एक निम्न विधियों का उपयोग करता है सुधार किया जा सकता Delegate से प्राप्त प्रकार पर विस्तार तरीके के रूप में दिखाई देते हैं, और इस तरह के प्रकार के उदाहरण के लिए जोड़ा या चर या उपयुक्त प्रतिनिधि प्रकार के क्षेत्रों से घटा दिया जाना करने देता है; इस तरह के जोड़ या घटाव थ्रेड-सुरक्षित फैशन में किया जाएगा, इसलिए इन विधियों का उपयोग अतिरिक्त लॉकिंग के बिना विधियों को जोड़ने/हटाने के तरीकों से करना संभव हो सकता है।

+0

बहुत उपयोगी, धन्यवाद! –

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

  • कोई संबंधित समस्या नहीं^_^