घटनाओं और प्रतिनिधियों और इसके संबंधित अनुप्रयोगों के बीच अंतर [बंद]


107

मुझे सिंटैक्टिकल शुगर होने के अलावा प्रतिनिधियों पर घटनाओं का उपयोग करने के फायदे नहीं दिखते। शायद मुझे गलतफहमी हो रही है, लेकिन ऐसा लगता है कि यह घटना सिर्फ प्रतिनिधि के लिए एक जगह है।

क्या आप मुझे अंतर समझाएंगे और कब कौन सा उपयोग करना है? फायदे और नुकसान क्या हैं? हमारा कोड घटनाओं से बहुत अधिक जुड़ा हुआ है, और मैं इसकी तह तक जाना चाहता हूं।

आप घटनाओं पर प्रतिनिधियों का उपयोग कब करेंगे और इसके विपरीत? कृपया अपने वास्तविक विश्व अनुभव को दोनों के साथ बताएं, उत्पादन कोड में कहें।


मतभेदों के आसपास मेरे सिर को लपेटना वास्तव में कठिन था, वे एक ही दिखते हैं और पहली नज़र में ऐसा ही करते हैं
रॉबर्ट गोल्ड


1
दो घटनाओं और प्रतिनिधियों के बीच अंतर तथ्य का विषय है, राय का नहीं। प्रश्न संबंधित अनुप्रयोगों के लिए पूछता है क्योंकि वे उन समस्याओं में अंतर को स्पष्ट करते हैं जो प्रौद्योगिकियां हल करती हैं। यह भी विचार का विषय नहीं है क्योंकि किसी ने भी नहीं पूछा कि कौन सबसे अच्छा था। इस सवाल का कोई हिस्सा राय का विषय नहीं है, और यह कथन भी राय नहीं है। मेरी राय में। क्या आपको अपना बैज मिला?
पीटर वॉन

जवाबों:


49

तकनीकी दृष्टिकोण से, अन्य उत्तरों ने मतभेदों को संबोधित किया है।

शब्दार्थ के नजरिए से, घटनाओं को किसी वस्तु द्वारा तब उठाया जाता है जब कुछ शर्तों को पूरा किया जाता है। उदाहरण के लिए, मेरे स्टॉक वर्ग के पास एक संपत्ति है जिसे लिमिट कहा जाता है, और यह एक घटना उठाता है जब स्टॉक की कीमतें सीमा तक पहुंच जाती हैं। यह सूचना एक ईवेंट के माध्यम से की जाती है। क्या वास्तव में किसी को भी इस घटना की परवाह है और इसकी सदस्यता लेना मालिक वर्ग की चिंता से परे है।

एक प्रतिनिधि C / C ++ शब्दों में पॉइंटर के समान निर्माण का वर्णन करने के लिए एक अधिक सामान्य शब्द है। .Net में सभी प्रतिनिधि बहुस्त्र्पीय प्रतिनिधि हैं। शब्दार्थ के दृष्टिकोण से, वे आम तौर पर एक तरह के इनपुट के रूप में उपयोग किए जाते हैं। विशेष रूप से, वे रणनीति पैटर्न को लागू करने का एक सही तरीका हैं । उदाहरण के लिए, यदि मैं वस्तुओं की सूची को क्रमबद्ध करना चाहता हूं, तो मैं कार्यान्वयन को बताने के लिए दो वस्तुओं की तुलना करने के तरीके के लिए एक तुलनित्र रणनीति प्रदान कर सकता हूं।

मैंने उत्पादन कोड में दो विधियों का उपयोग किया है। जब कुछ संपत्तियों की पूर्ति होती है, तो मेरे डेटा ऑब्जेक्ट्स को सूचित किया जाता है। सबसे बुनियादी उदाहरण, जब भी कोई संपत्ति बदलती है, तो एक PropertyChanged घटना को उठाया जाता है (INotifyPropertyChanged इंटरफ़ेस देखें)। मैंने कुछ वस्तुओं को स्ट्रिंग में बदलने की विभिन्न रणनीतियों को प्रदान करने के लिए कोड में प्रतिनिधियों का उपयोग किया है। यह विशेष उदाहरण उपयोगकर्ताओं को प्रदर्शित करने के लिए किसी विशेष ऑब्जेक्ट प्रकार के कार्यान्वयन की एक गौरवशाली ToString () सूची थी।


4
शायद मुझे कुछ याद आ रहा है, लेकिन एक इवेंट हैंडलर का प्रतिनिधि नहीं है?
19

1
मेरा उत्तर प्रश्नों को संबोधित करता है # 1 और # 2 संपादित करें; उपयोग के दृष्टिकोण से अंतर। इस चर्चा के प्रयोजनों के लिए, वे अलग हैं, भले ही एक तकनीकी दृष्टिकोण से, आप सही हैं। तकनीकी अंतर के अन्य उत्तरों पर एक नज़र डालें।
सिजमन रोजगा

3
".Net में सभी प्रतिनिधि बहुस्त्र्पीय प्रतिनिधि हैं"? यहां तक ​​कि प्रतिनिधि जो मान लौटाते हैं?
क्वर्टी

5
हाँ। इतिहास के लिए, msdn.microsoft.com/en-us/magazine/cc301816.aspx पर एक नज़र डालें । देखें: msdn.microsoft.com/en-us/library/system.delegate.aspx । यदि वे मान लौटाते हैं, तो जो मान लौटाया जाता है वह श्रृंखला में अंतिम प्रतिनिधि का निष्कासन है।
सिजमन रोजगा 3

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

55

कीवर्ड eventमल्टीकास्ट प्रतिनिधियों के लिए एक गुंजाइश संशोधक है। इस और केवल एक बहुस्त्र्पीय प्रतिनिधि की घोषणा के बीच व्यावहारिक अंतर इस प्रकार हैं:

  • आप eventएक इंटरफ़ेस में उपयोग कर सकते हैं ।
  • मल्टीकास्ट प्रतिनिधि के लिए आह्वान पहुंच घोषणा वर्ग तक सीमित है। व्यवहार ऐसा है मानो प्रतिनिधिमंडल मंगलाचरण के लिए निजी था। असाइनमेंट के प्रयोजनों के लिए, पहुंच एक स्पष्ट पहुंच संशोधक (जैसे public event) द्वारा निर्दिष्ट है ।

ब्याज की बात है, तो आप आवेदन कर सकते हैं +और -प्रतिनिधियों बहुस्त्र्पीय के लिए, और इस का आधार है +=और -=घटनाओं के लिए प्रतिनिधियों का संयोजन कार्य के लिए वाक्य रचना। ये तीन स्निपेट बराबर हैं:

B = new EventHandler(this.MethodB);
C = new EventHandler(this.MethodC);
A = B + C;

नमूना दो, प्रत्यक्ष असाइनमेंट और संयोजन असाइनमेंट दोनों को दिखाता है।

B = new EventHandler(this.MethodB);
C = new EventHandler(this.MethodC);
A = B;
A += C;

नमूना तीन: अधिक परिचित वाक्यविन्यास। आप शायद सभी हैंडलर को हटाने के लिए अशक्त के कार्य से परिचित हैं।

B = new EventHandler(this.MethodB);
C = new EventHandler(this.MethodC);
A = null;
A += B;
A += C;

गुणों की तरह, घटनाओं में एक पूर्ण सिंटैक्स होता है जो कोई भी कभी भी उपयोग नहीं करता है। यह:

class myExample 
{
  internal EventHandler eh;

  public event EventHandler OnSubmit 
  { 
    add 
    {
      eh = Delegate.Combine(eh, value) as EventHandler;
    }
    remove
    {
      eh = Delegate.Remove(eh, value) as EventHandler;
    }
  }

  ...
}

... बिल्कुल ऐसा ही करता है :

class myExample 
{
  public event EventHandler OnSubmit;
}

ऐड और रिमूवल मेथड्स स्टैब्लेटेड सिंटैक्स में अधिक स्पष्ट हैं जो VB.NET उपयोग करता है (कोई ऑपरेटर अधिभार नहीं)।


6
+ "मल्टीकास्ट प्रतिनिधि के लिए आह्वान पहुंच घोषणा वर्ग के लिए सीमित है" - यह मेरे लिए प्रतिनिधियों और घटनाओं के बीच महत्वपूर्ण अंतर बिंदु है।
रिचर्ड एनडी

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

4
गूगल और स्टैकओवरफ्लो जितना आसान हो सकता है, यह सब और अधिक सी # भाषा कल्पना में मन-सुन्न विवरण में उपलब्ध है, सार्वजनिक रूप से Microsoft से बिना किसी शुल्क के उपलब्ध है। मुझे पता है कि इसके चेहरे पर, भगवान ने मैनुअल बनाया और जॉन स्कीट ने इसे निगल लिया, लेकिन अन्य प्रतियां भी हैं :)
पीटर वॉन

12

घटनाएँ वाक्यात्मक चीनी हैं। वे स्वादिष्ट हैं। जब मुझे कोई घटना दिखाई देती है, तो मुझे पता होता है कि मुझे क्या करना है। जब मैं एक प्रतिनिधि को देखता हूं, तो मुझे यकीन नहीं होता।

इंटरफेस (अधिक चीनी) के साथ घटनाओं को मिलाकर एक मुंह में पानी लाने वाला स्नैक बनता है। डेलिगेट्स और शुद्ध आभासी अमूर्त वर्ग बहुत कम स्वादिष्ट होते हैं।


मैं इसे भी इसी तरह देखता हूं। मैं गहरी और अधिक मीठी व्याख्या चाहता हूं :)

13
बहुत अधिक चीनी एक वसा बनाती है, हालांकि ... = पी
एरिक फोर्ब्स

5

मेटाडेटा में ईवेंट को ऐसे चिह्नित किया जाता है। यह विंडोज फॉर्म या ASP.NET डिजाइनरों जैसी चीजों को प्रतिनिधि प्रकार के गुणों से घटनाओं को भेद करने की अनुमति देता है, और उनके लिए उचित समर्थन प्रदान करता है (विशेष रूप से उन्हें गुण विंडो के घटनाक्रम टैब पर दिखा रहा है)।

प्रतिनिधि प्रकार की संपत्ति से एक और अंतर यह है कि उपयोगकर्ता केवल ईवेंट हैंडलर जोड़ और हटा सकते हैं, जबकि प्रतिनिधि प्रकार की संपत्ति के साथ वे मूल्य निर्धारित कर सकते हैं:

someObj.SomeCallback = MyCallback;  // okay, replaces any existing callback
someObj.SomeEvent = MyHandler;  // not okay, must use += instead

यह ईवेंट ग्राहकों को अलग करने में मदद करता है: मैं अपने हैंडलर को किसी ईवेंट में जोड़ सकता हूं, और आप अपने हैंडलर को उसी ईवेंट में जोड़ सकते हैं, और आप गलती से मेरे हैंडलर को अधिलेखित नहीं करेंगे।


4

हालांकि घटनाओं को आमतौर पर मल्टीकास्ट प्रतिनिधियों के साथ लागू किया जाता है, लेकिन इस बात की कोई आवश्यकता नहीं है कि उनका उपयोग इस तरह से किया जाए। यदि एक वर्ग घटना को उजागर करता है, तो इसका मतलब है कि कक्षा दो तरीकों को उजागर करती है। उनके अर्थ हैं, संक्षेप में:

  1. यहाँ एक प्रतिनिधि है। जब कुछ दिलचस्प होता है तो कृपया इसे लागू करें।
  2. यहाँ एक प्रतिनिधि है। आपको इसे जितनी जल्दी हो सके सभी संदर्भ को नष्ट कर देना चाहिए (और अब इसे कॉल नहीं करना चाहिए)।

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


4

मतभेदों को समझने के लिए आप इस 2 उदाहरणों को देख सकते हैं

प्रतिनिधि के साथ छूट (इस मामले में कार्रवाई जो एक प्रकार का प्रतिनिधि है जो मूल्य वापस नहीं करता है)

public class Animal
{
    public Action Run {get; set;}

    public void RaiseEvent()
    {
        if (Run != null)
        {
            Run();
        }
    }
}

प्रतिनिधि का उपयोग करने के लिए आपको कुछ ऐसा करना चाहिए

Animale animal= new Animal();
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running") ;
animal.RaiseEvent();

यह कोड अच्छी तरह से काम करता है लेकिन आपके पास कुछ कमजोर स्पॉट हो सकते हैं।

उदाहरण के लिए अगर मैं यह लिखता हूं

animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running");
animal.Run = () => Console.WriteLine("I'm sleeping") ;

कोड की अंतिम पंक्ति के साथ मैंने पिछले व्यवहारों को केवल एक लापता के साथ ओवरराइड किया था +(मैंने +इसके बजाय उपयोग किया है +=)

एक और कमजोर जगह यह है कि हर वर्ग जो आपकी Animalकक्षा का उपयोग करता है, RaiseEventवह इसे कॉल कर सकता है animal.RaiseEvent()

इस कमजोर धब्बों से बचने के लिए आप eventsc # का उपयोग कर सकते हैं ।

आपका पशु वर्ग इस तरह से बदल जाएगा

public class ArgsSpecial :EventArgs
   {
        public ArgsSpecial (string val)
        {
            Operation=val;
        }

        public string Operation {get; set;}
   } 



 public class Animal
    {
       public event EventHandler<ArgsSpecial> Run = delegate{} //empty delegate. In this way you are sure that value is always != null because no one outside of the class can change it

       public void RaiseEvent()
       {  
          Run(this, new ArgsSpecial("Run faster"));
       }
    }

घटनाओं को कॉल करने के लिए

 Animale animal= new Animal();
 animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
 animal.RaiseEvent();

अंतर:

  1. आप सार्वजनिक संपत्ति का उपयोग नहीं कर रहे हैं, लेकिन एक सार्वजनिक फ़ील्ड (ईवेंट्स के साथ कंपाइलर आपके खेतों को अवांछित पहुंच से बचाता है)
  2. घटनाओं को सीधे नहीं सौंपा जा सकता है। इस मामले में आप पिछली त्रुटि नहीं कर सकते हैं जो मैंने व्यवहार को ओवरराइड करने के साथ दिखाया है।
  3. आपकी कक्षा के बाहर कोई भी इस घटना को नहीं बढ़ा सकता।
  4. घटनाओं को एक इंटरफ़ेस घोषणा में शामिल किया जा सकता है, जबकि एक क्षेत्र नहीं कर सकता

टिप्पणियाँ

EventHandler निम्नलिखित प्रतिनिधि के रूप में घोषित किया जाता है:

public delegate void EventHandler (object sender, EventArgs e)

यह एक प्रेषक (वस्तु प्रकार) और घटना तर्क लेता है। यदि यह स्थिर विधियों से आता है तो प्रेषक अशक्त है।

आप EventHAndlerइस उदाहरण का उपयोग करने के बजाय इसका उपयोग भी कर सकते हैंEventHandler<ArgsSpecial>

EventHandler के बारे में प्रलेखन के लिए यहाँ देखें


3

# 1 संपादित करें आप घटनाओं और बनाम पर प्रतिनिधियों का उपयोग कब करेंगे? कृपया अपने वास्तविक विश्व अनुभव को दोनों के साथ बताएं, उत्पादन कोड में कहें।

जब मैं अपने स्वयं के एपीआई डिजाइन करता हूं, तो मैं प्रतिनिधियों को परिभाषित करता हूं जो कि तरीकों के मापदंडों के रूप में पारित किए जाते हैं, या कक्षाओं के निर्माणकर्ताओं के लिए:

  • ताकि एक विधि एक सरल 'टेम्पलेट विधि' पैटर्न को लागू कर सके (जैसे कि। Predicateऔर Actionप्रतिनिधियों को .Net सामान्य संग्रह कक्षाओं में पास किया जाता है)
  • या इसलिए कि वर्ग एक 'कॉलबैक' कर सकता है (आमतौर पर उस तरीके की कॉलबैक जो इसे बनाया गया है)।

ये प्रतिनिधि आम तौर पर रन-टाइम (यानी नहीं होना चाहिए null) में गैर-वैकल्पिक होते हैं

मैं घटनाओं का उपयोग नहीं करता हूं; लेकिन जहां मैं घटनाओं का उपयोग करता हूं, मैं उन्हें वैकल्पिक रूप से सिग्नलिंग घटनाओं के लिए शून्य, एक, या अधिक क्लाइंट्स के लिए उपयोग करता हूं जो रुचि हो सकती है, अर्थात जब यह समझ में आता है कि एक वर्ग (जैसे System.Windows.Formवर्ग) मौजूद होना चाहिए और कोई क्लाइंट होना चाहिए या नहीं अपने ईवेंट हैंडलर को अपने ईवेंट में शामिल किया (जैसे कि फॉर्म का 'माउस डाउन' ईवेंट मौजूद है, लेकिन यह वैकल्पिक है कि कोई भी बाहरी क्लाइंट उस ईवेंट हैंडलर को इंस्‍टॉल करने में रुचि रखता है)।


2

हालाँकि मुझे इसके लिए कोई तकनीकी कारण नहीं मिला है, मैं यूआई शैली कोड में घटनाओं का उपयोग करता हूं, दूसरे शब्दों में, कोड के उच्च स्तरों में, और कोड में गहराई से रहने वाले तर्क के लिए प्रतिनिधियों का उपयोग करता हूं। जैसा कि मैं कहता हूं कि आप या तो उपयोग कर सकते हैं, लेकिन मुझे यह उपयोग पैटर्न तार्किक रूप से लगता है, यदि और कुछ नहीं, तो यह कॉलबैक के प्रकार और उनके पदानुक्रम को भी दस्तावेज़ करने में मदद करता है।


संपादित करें: मुझे लगता है कि मेरे द्वारा उपयोग किए जाने वाले पैटर्न में अंतर होगा, मुझे लगता है कि यह घटनाओं को अनदेखा करने के लिए पूरी तरह से स्वीकार्य है, वे हुक / स्टब्स हैं, अगर आपको घटना के बारे में जानने की जरूरत है, तो उन्हें सुनें, अगर आपको परवाह नहीं है घटना बस इसे अनदेखा करें। यही कारण है कि मैं उन्हें यूआई, टाइपो जावास्क्रिप्ट / ब्राउज़र इवेंट स्टाइल के लिए उपयोग करता हूं। हालाँकि, जब मेरे पास एक प्रतिनिधि होता है, तो मुझे उम्मीद है कि वास्तव में किसी को प्रतिनिधि के कार्य को संभालने की उम्मीद है, और यदि नहीं संभाला तो एक अपवाद फेंक दें।


क्या आप इसके बारे में विस्तार से बताएंगे कि जैसे ही मैं यूआई में बुराइयों का उपयोग करता हूं? एक अच्छा उदाहरण पर्याप्त होगा .... धन्यवाद

1

घटनाओं और प्रतिनिधियों के बीच का अंतर मेरे विचार से बहुत छोटा है .. मैंने अभी इस विषय पर एक सुपर शॉर्ट यूट्यूब वीडियो पोस्ट किया है: https://www.youtube.com/watch?v=el-kKK-7SBU

उम्मीद है की यह मदद करेगा!


2
ढेर अतिप्रवाह में आपका स्वागत है! जब भी यह सैद्धांतिक रूप से प्रश्न का उत्तर दे सकता है, तो यहां उत्तर के आवश्यक भागों को शामिल करना और संदर्भ के लिए लिंक प्रदान करना बेहतर होगा
भूतकूट

1

यदि हम ईवेंट के स्थान पर केवल डेलीगेट का उपयोग करते हैं तो सब्सक्राइबर के पास प्रतिरूप में क्लोन (), इनवोक () को स्वयं दिखाने का अवसर है। जो सही नहीं है।

यहां छवि विवरण दर्ज करें

यह मुख्य अंतर है b / w घटना और प्रतिनिधि। सब्सक्राइबर के पास केवल एक अधिकार है यानी घटनाओं को सुनना

ConsoleLog वर्ग EventLogHandler के माध्यम से लॉग ईवेंट की सदस्यता ले रहा है

public class ConsoleLog
{
    public ConsoleLog(Operation operation)
    {
        operation.EventLogHandler += print;
    }

    public void print(string str)
    {
        Console.WriteLine("write on console : " + str);
    }
}

FileLog वर्ग EventLogHandler के माध्यम से लॉग ईवेंट की सदस्यता ले रहा है

public class FileLog
{
    public FileLog(Operation operation)
    {
        operation.EventLogHandler += print;
    }

    public void print(string str)
    {
        Console.WriteLine("write in File : " + str);
    }
}

ऑपरेशन क्लास लॉग इवेंट्स प्रकाशित कर रहा है

public delegate void logDelegate(string str);
public class Operation
{
    public event logDelegate EventLogHandler;
    public Operation()
    {
        new FileLog(this);
        new ConsoleLog(this);
    }

    public void DoWork()
    {
        EventLogHandler.Invoke("somthing is working");
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.