2008-09-24 9 views
19

हर बार जब मैं सी # प्रोजेक्ट में गहराई से शुरू करता हूं, तो मैं कई घटनाओं के साथ समाप्त होता हूं जो वास्तव में केवल एक आइटम को पास करने की आवश्यकता होती है। मैं EventHandler/EventArgs अभ्यास के साथ चिपके रहते हैं, लेकिन मुझे क्या करना चाहते की तरह कुछ है:.NET EventHandlers - जेनेरिक या नहीं?

public delegate void EventHandler<T>(object src, EventArgs<T> args); 

public class EventArgs<T>: EventArgs { 

    private T item; 

    public EventArgs(T item) { 
    this.item = item; 
    } 

    public T Item { 
    get { return item; } 
    } 
} 

बाद में, मैं हो सकता है मेरी

public event EventHandler<Foo> FooChanged; 

public event EventHandler<Bar> BarChanged; 

हालांकि, ऐसा लगता है कि नेट के लिए मानक प्रत्येक प्रकार की घटना के लिए एक नया प्रतिनिधि और EventArgs सबक्लास बनाना है। क्या मेरे सामान्य दृष्टिकोण में कुछ गड़बड़ है?


संपादित करें: इस पोस्ट का कारण यह है कि मैंने इसे एक नई परियोजना में फिर से बनाया है, और यह सुनिश्चित करना चाहता था कि यह ठीक था। दरअसल, मैं इसे पोस्ट कर रहा था जैसा कि मैंने पोस्ट किया था। मैंने पाया कि एक सामान्य EventHandler<TEventArgs> है, इसलिए आपको जेनेरिक प्रतिनिधि बनाने की आवश्यकता नहीं है, लेकिन आपको अभी भी सामान्य EventArgs<T> कक्षा की आवश्यकता है, क्योंकि TEventArgs: EventArgs
एक और संपादित करें: एक नकारात्मक पक्ष यह है (मेरे लिए) में निर्मित समाधान के अतिरिक्त शब्दाडंबर है:

public event EventHandler<EventArgs<Foo>> FooChanged; 

बनाम

public event EventHandler<Foo> FooChanged; 

यह ग्राहकों के लिए रजिस्टर करने के लिए के लिए एक दर्द हो सकता है आपके हालाँकि घटनाएं, क्योंकि सिस्टम नेमस्पेस डिफ़ॉल्ट रूप से आयात किया जाता है, इसलिए उन्हें अपने नामस्थान को मैन्युअल रूप से खोजना होगा, यहां तक ​​कि रेसर्पर जैसे फैंसी टूल के साथ ... किसी के पास उससे संबंधित कोई विचार है?

+1

सीआरयूडी-शैली के लिए आपने अन्य टिप्पणी में उल्लेख किया है, मेरे पास EntityEventHandler होगा जो स्वयं वर्णनात्मक होगा। –

+1

आप जोड़ सकते हैं: FooArgs = Namespace.EventArgs का उपयोग करके; जो घटना को वापस साफ कर देगा - सार्वजनिक कार्यक्रम EventHandler FooChanged; – Fraser

उत्तर

26

प्रतिनिधि प्रपत्र .नेट फ्रेमवर्क के बाद से जोड़ दिया गया है 2,0

public delegate void EventHandler<TArgs>(object sender, TArgs args) where TArgs : EventArgs 

आप दृष्टिकोण, आगे एक सा हो जाता है के बाद से उपलब्ध कराने के बाहर के बॉक्स एकल डेटा आइटम के साथ EventArgs के लिए कार्यान्वयन, लेकिन यह मूल विचार के कई गुण का अभाव :

  1. आप निर्भर कोड को बदलने के बिना ईवेंट डेटा में और अधिक गुण नहीं जोड़ सकते हैं। ईवेंट ग्राहक को अधिक डेटा प्रदान करने के लिए आपको प्रतिनिधि हस्ताक्षर को बदलना होगा।
  2. आपकी डेटा ऑब्जेक्ट सामान्य है, लेकिन यह "अज्ञात" भी है, और कोड पढ़ने के दौरान आपको "आइटम" संपत्ति को उपयोग से समझना होगा। इसे नामित डेटा के अनुसार नामित किया जाना चाहिए।
  3. जेनिक्स का उपयोग इस तरह से आप EventArgs के समानांतर पदानुक्रम नहीं बना सकते हैं, जब आपके पास अंतर्निहित (आइटम) प्रकारों का पदानुक्रम होता है। जैसे EventArgs < बेसटाइप > EventArgs <DerivedType> के लिए आधार प्रकार नहीं है, भले ही बेसटाइप DerivedType के लिए आधार हो।

तो, मुझे लगता है कि यह सामान्य eventhandler < टी > उपयोग करने के लिए बेहतर है, लेकिन अभी भी कस्टम EventArgs कक्षाएं, डेटा मॉडल की आवश्यकताओं के अनुसार संगठित है। विजुअल स्टूडियो और रीशेर्पर जैसे एक्सटेंशन के साथ, यह केवल नए आदेश बनाने के लिए कुछ कमांडों का मामला है।

+0

नहीं है, इसलिए, यदि आपके पास 20 अलग-अलग वर्गों वाला डेटा मॉडल है, तो आप उनमें से प्रत्येक के लिए EventArgs बनायेंगे? –

+0

@ क्रिस मैरास्टी-जॉर्ज यह विभिन्न आकारों और उनके संबंधित डेटा की संख्या पर निर्भर करता है, मॉडल आकार पर नहीं। यदि आपके सभी वर्गों को सरल संपत्तिChanging/PropertyChanged ईवेंट आग लगती है, तो आपके पास PropertyName डेटा के साथ एक EventArgs उत्तराधिकारी होगा। –

+0

एक सीआरयूडी प्रकार सेवा का मानना ​​- आपके पास प्रति आइटम प्रकार, आइटमक्रेटेड, आइटम अपडेटेड, आइटम हटाए गए 3 ईवेंट होंगे। मुझे लगता है कि पहले 2 आइटम की एक प्रति, और अंतिम, शायद इसकी आईडी के साथ गुजरना चाहिए। यदि सीआरयूडी सेवा 20 आइटम प्रकारों को संभाल सकती है, तो आप 21 EventArgs उप-वर्गों को देख रहे हैं। –

7

नहीं, मुझे नहीं लगता कि यह गलत दृष्टिकोण है। मुझे लगता है कि यह [शानदार] पुस्तक Framework Design Guidelines में भी अनुशंसा की जाती है। मैं भी यही करता हूं।

1

मुझे विश्वास है कि .NET के हाल के संस्करणों में ऐसे ही एक ईवेंट हैंडलर परिभाषित हैं। जहां तक ​​मेरा संबंध है, यह एक बड़ा अंगूठा है।

/संपादित करें

वहाँ मूल रूप से भेद नहीं मिला। जब तक आप EventArgs से प्राप्त होने वाली कक्षा को वापस ले रहे हैं, जो आप हैं, मुझे कोई समस्या नहीं दिखाई दे रही है। यदि आप रखरखाव के कारणों के परिणाम को लपेट नहीं रहे थे तो मुझे चिंता होगी। मैं अभी भी कहता हूं कि यह मेरे लिए अच्छा लग रहा है।

+0

हाल के संस्करणों में सामान्य प्रतिनिधि हैं, लेकिन उनके पास सिंगल-आइटम EventArgs –

3

यह सही कार्यान्वयन है। इसे जेनेटिक्स पहले उपलब्ध (2.0) के बाद से .NET Framework (mscorlib) में जोड़ा गया है।

इसके उपयोग और कार्यान्वयन पर अधिक जानकारी के लिए MSDN देखें: http://msdn.microsoft.com/en-us/library/db0etb8x.aspx

2

के बाद से नेट 2,0

EventHandler<T>

लागू किया गया है।

3

पहली बार मैंने इस छोटे पैटर्न को देखा, मैं एमएस पैटर्न & प्रथाओं समूह से Composite UI Application block का उपयोग कर रहा था।

यह मुझे कोई लाल झंडा नहीं फेंकता है; वास्तव में यह DRY नियम का पालन करने के लिए जेनरिक का लाभ उठाने का एक स्मार्ट तरीका भी है।

2

आप मुझे सामान्य eventhandler बड़े पैमाने पर उपयोग किया गया है MSDN http://msdn.microsoft.com/en-us/library/db0etb8x.aspx

पर जेनेरिक eventhandler खोजने के लिए और तथाकथित "प्रकार का धमाका (वर्ग)" को रोकने के लिए कर रहा था कर सकते हैं परियोजना छोटे और आसपास नेविगेट करने के लिए आसान रखा गया था।

गैर सामान्य eventhandler प्रतिनिधि के लिए एक नया सहज ज्ञान युक्त एक प्रतिनिधि के साथ आ रहा है दर्दनाक है और निम्न में से मौजूदा प्रकार के साथ ओवरलैप जोड़कर "* eventhandler" नए प्रतिनिधि नाम करने के लिए मेरी राय में ज्यादा मदद नहीं करता है

9

सामान्य घटना घोषणा को आसान बनाने के लिए, मैंने इसके लिए कुछ कोड स्निपेट बनाए। उनका उपयोग करने के लिए:

  • पूरे स्निपेट की प्रतिलिपि बनाएँ।
  • इसे एक टेक्स्ट फ़ाइल में पेस्ट करें (उदा। नोटपैड में)।
  • फ़ाइल को .snippet एक्सटेंशन से सहेजें।
  • जैसे, अपने उचित टुकड़ा निर्देशिका में .snippet फ़ाइल रखो:

विजुअल स्टूडियो 2008 \ कोड स्निपेट्स \ विजुअल C# \ मेरे कोड स्निपेट्स

यहाँ एक एक कस्टम EventArgs वर्ग का उपयोग करता है है से एक ही प्रॉपर्टी:

<?xml version="1.0" encoding="utf-8" ?> 
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> 
    <CodeSnippet Format="1.0.0"> 
     <Header> 
      <Title>Generic event with one type/argument.</Title> 
      <Shortcut>ev1Generic</Shortcut> 
      <Description>Code snippet for event handler and On method</Description> 
      <Author>Kyralessa</Author> 
      <SnippetTypes> 
       <SnippetType>Expansion</SnippetType> 
      </SnippetTypes> 
     </Header> 
     <Snippet> 
      <Declarations> 
     <Literal> 
      <ID>type</ID> 
      <ToolTip>Type of the property in the EventArgs subclass.</ToolTip> 
      <Default>propertyType</Default> 
     </Literal> 
     <Literal> 
      <ID>argName</ID> 
      <ToolTip>Name of the argument in the EventArgs subclass constructor.</ToolTip> 
      <Default>propertyName</Default> 
     </Literal> 
     <Literal> 
      <ID>propertyName</ID> 
      <ToolTip>Name of the property in the EventArgs subclass.</ToolTip> 
      <Default>PropertyName</Default> 
     </Literal> 
     <Literal> 
      <ID>eventName</ID> 
      <ToolTip>Name of the event</ToolTip> 
      <Default>NameOfEvent</Default> 
     </Literal> 
      </Declarations> 
     <Code Language="CSharp"><![CDATA[public class $eventName$EventArgs : System.EventArgs 
     { 
     public $eventName$EventArgs($type$ $argName$) 
     { 
      this.$propertyName$ = $argName$; 
     } 

     public $type$ $propertyName$ { get; private set; } 
     } 

     public event EventHandler<$eventName$EventArgs> $eventName$; 
      protected virtual void On$eventName$($eventName$EventArgs e) 
      { 
       var handler = $eventName$; 
       if (handler != null) 
        handler(this, e); 
      }]]> 
     </Code> 
     </Snippet> 
    </CodeSnippet> 
</CodeSnippets> 

और यहाँ एक से दो गुण है कि है:

<?xml version="1.0" encoding="utf-8" ?> 
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> 
    <CodeSnippet Format="1.0.0"> 
    <Header> 
     <Title>Generic event with two types/arguments.</Title> 
     <Shortcut>ev2Generic</Shortcut> 
     <Description>Code snippet for event handler and On method</Description> 
     <Author>Kyralessa</Author> 
     <SnippetTypes> 
     <SnippetType>Expansion</SnippetType> 
     </SnippetTypes> 
    </Header> 
    <Snippet> 
     <Declarations> 
     <Literal> 
      <ID>type1</ID> 
      <ToolTip>Type of the first property in the EventArgs subclass.</ToolTip> 
      <Default>propertyType1</Default> 
     </Literal> 
     <Literal> 
      <ID>arg1Name</ID> 
      <ToolTip>Name of the first argument in the EventArgs subclass constructor.</ToolTip> 
      <Default>property1Name</Default> 
     </Literal> 
     <Literal> 
      <ID>property1Name</ID> 
      <ToolTip>Name of the first property in the EventArgs subclass.</ToolTip> 
      <Default>Property1Name</Default> 
     </Literal> 
     <Literal> 
      <ID>type2</ID> 
      <ToolTip>Type of the second property in the EventArgs subclass.</ToolTip> 
      <Default>propertyType1</Default> 
     </Literal> 
     <Literal> 
      <ID>arg2Name</ID> 
      <ToolTip>Name of the second argument in the EventArgs subclass constructor.</ToolTip> 
      <Default>property1Name</Default> 
     </Literal> 
     <Literal> 
      <ID>property2Name</ID> 
      <ToolTip>Name of the second property in the EventArgs subclass.</ToolTip> 
      <Default>Property2Name</Default> 
     </Literal> 
     <Literal> 
      <ID>eventName</ID> 
      <ToolTip>Name of the event</ToolTip> 
      <Default>NameOfEvent</Default> 
     </Literal> 
     </Declarations> 
     <Code Language="CSharp"> 
     <![CDATA[public class $eventName$EventArgs : System.EventArgs 
     { 
     public $eventName$EventArgs($type1$ $arg1Name$, $type2$ $arg2Name$) 
     { 
      this.$property1Name$ = $arg1Name$; 
      this.$property2Name$ = $arg2Name$; 
     } 

     public $type1$ $property1Name$ { get; private set; } 
     public $type2$ $property2Name$ { get; private set; } 
     } 

     public event EventHandler<$eventName$EventArgs> $eventName$; 
      protected virtual void On$eventName$($eventName$EventArgs e) 
      { 
       var handler = $eventName$; 
       if (handler != null) 
        handler(this, e); 
      }]]> 
     </Code> 
    </Snippet> 
    </CodeSnippet> 
</CodeSnippets> 

आप उन्हें जितनी चाहें उतनी संपत्तियों के साथ बनाने के लिए पैटर्न का अनुसरण कर सकते हैं।

1

उपयोग सामान्य ईवेंट हैंडलर उदाहरणों

.NET फ्रेमवर्क 2.0 से पहले, आदेश ईवेंट हैंडलर में कस्टम जानकारी पारित करने के लिए, एक नया प्रतिनिधि घोषित किया जाना चाहिए कि एक वर्ग System.EventArgs वर्ग से प्राप्त निर्दिष्ट किया था। यह अब .NET

फ्रेमवर्क 2.0, जो System.EventHandler < T> प्रस्तुत किया गया है, में अब सत्य नहीं है। यह सामान्य प्रतिनिधि ईवेंट हैंडलर के साथ इवेंटएर्ग से प्राप्त किसी भी वर्ग को अनुमति देता है।

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