प्रतिनिधियों और घटनाओं के बीच अंतर क्या हैं?


317

प्रतिनिधियों और घटनाओं के बीच अंतर क्या हैं? दोनों ही ऐसे कार्यों के संदर्भ नहीं हैं जिन्हें निष्पादित किया जा सकता है?



2
यह उदाहरण के साथ समझाता है एक नज़र unitygeek.com/delegates-events-unity
राहुल ललित

जवाबों:


282

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


44
यदि निश्चित रूप से, यह सुरक्षा परत "क्लाइंट" ( प्रतिनिधि वर्ग / संरचना के बाहर कोड) को प्रतिनिधि को लागू करने से रोकता है , और किसी भी तरह से प्रतिनिधि वस्तु को "पीछे" घटना से प्राप्त करने से रोकता है ।
जेपी स्टिग नील्सन

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

3
@mmcdole आप उसकी व्याख्या करने के लिए एक उदाहरण प्रदान कर सकते हैं?
विवेक नं।

103

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

प्रतिनिधि के साथ उदाहरण (इस मामले में, एक कार्य - यह एक प्रकार का प्रतिनिधि है जो मान वापस नहीं करता है)

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

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

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

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

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

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

 Animal 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<ArgsSpecial>, EventHandlerइसके बजाय का उपयोग करके भी लिखा जा सकता है ।

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


7
जब तक मैं भाग नहीं सकता तब तक सब कुछ बहुत अच्छा लग रहा था "आपकी कक्षा के बाहर कोई भी इस घटना को नहीं उठा सकता है।" इसका क्या मतलब है? क्या कोई RaiseEventतब तक कॉल नहीं कर सकता जब तक कि कॉलिंग विधि animalमें उस कोड का एक उदाहरण तक पहुंच नहीं है जो घटना का उपयोग करता है?
नृत्य 2

11
@ सुंग घटनाओं को केवल कक्षा के अंदर से ही उठाया जा सकता है, शायद मैं स्पष्ट नहीं कर रहा हूं कि समझा रहा हूं। ईवेंट के साथ आप उस फ़ंक्शन को कॉल कर सकते हैं जो ईवेंट को बढ़ाता है (इनकैप्सुलेशन), लेकिन इसे केवल क्लास के अंदर से ही परिभाषित किया जा सकता है। अगर मुझे स्पष्ट नहीं है तो मुझे बताएं।
faby

1
"ईवेंट को सीधे असाइन नहीं किया जा सकता है।" जब तक मैं आपको गलत न समझ लूं, यह सच नहीं है। यहाँ एक उदाहरण है: gist.github.com/Chiel92/36bb3a2d2ac7dd511b96
Chiel दस Brinke

2
@faby, आपका मतलब है कि भले ही इस कार्यक्रम को सार्वजनिक घोषित कर दिया गया हो, फिर भी मैं ऐसा नहीं कर सकता animal.Run(this, new ArgsSpecial("Run faster");?
पैप

1
@ChieltenBrinke बेशक घटना को कक्षा के सदस्यों के भीतर सौंपा जा सकता है ... लेकिन अन्यथा नहीं।
जिम बेल्टर

94

सिंटैक्टिक और ऑपरेशनल गुणों के अलावा, एक शब्दार्थिक अंतर भी है।

प्रतिनिधि हैं, वैचारिक रूप से, फ़ंक्शन टेम्पलेट; यह है, वे एक अनुबंध व्यक्त करते हैं कि एक फ़ंक्शन को प्रतिनिधि के "प्रकार" के रूप में माना जाना चाहिए।

घटनाओं का प्रतिनिधित्व करते हैं ... अच्छी तरह से, घटनाओं। वे किसी को कुछ होने पर सचेत करने का इरादा रखते हैं और हाँ, वे एक प्रतिनिधि परिभाषा का पालन करते हैं लेकिन वे एक ही चीज़ नहीं हैं।

यहां तक ​​कि अगर वे वास्तव में एक ही चीज थे (संयोगवश और आईएल कोड में) अभी भी शब्दार्थ अंतर रहेगा। सामान्य तौर पर मैं दो अलग-अलग अवधारणाओं के लिए दो अलग-अलग नाम रखना पसंद करता हूं, भले ही वे एक ही तरीके से लागू हों (जिसका मतलब यह नहीं है कि मुझे एक ही कोड दो बार पसंद है)।


8
डेलीगेट्स का उत्कृष्ट विवरण।
सैम्पसन

1
तो क्या हम कह सकते हैं कि एक घटना एक "विशेष" प्रतिनिधि का प्रकार है?
पापा

मुझे आपकी बात नहीं आती। आप किसी प्रतिनिधि को 'किसी को कुछ होने पर सतर्क करने के लिए' का उपयोग कर सकते हैं। शायद आप ऐसा नहीं करेंगे, लेकिन आप कर सकते हैं और इसलिए यह घटना की एक अंतर्निहित संपत्ति नहीं है।
स्टीव

@ जोर्ज कॉर्डोबा उदाहरण के प्रतिनिधि और घटनाओं के प्रतिनिधि एक अखबार के मालिक और घटनाएं हैं (सदस्यता लें या सदस्यता समाप्त करें) और कुछ लोग अखबार खरीदते हैं और कुछ लोग अखबार नहीं खरीदते हैं, जिसका अर्थ है कि अखबार का मालिक प्रत्येक व्यक्ति को अखबार खरीदने के लिए मजबूर नहीं कर सकता है। सही या गलत?
राहुल_पटील

37

यहाँ एक और अच्छा लिंक है। http://csharpindepth.com/Articles/Chapter2/Events.aspx

संक्षेप में, लेख से दूर ले जाओ - घटनाक्रम प्रतिनिधियों पर इनकैप्सुलेशन हैं।

लेख से उद्धरण:

मान लीजिए कि ईवेंट C # /। NET में एक अवधारणा के रूप में मौजूद नहीं थे। कोई अन्य वर्ग किसी घटना की सदस्यता कैसे लेगा? तीन विकल्प:

  1. एक सार्वजनिक प्रतिनिधि चर

  2. एक प्रतिनिधि चर एक संपत्ति द्वारा समर्थित है

  3. AddXXXHandler और RemoveXXXHandler विधियों के साथ एक प्रतिनिधि चर

विकल्प 1 स्पष्ट रूप से भयानक है, सभी सामान्य कारणों से हम सार्वजनिक चर को घृणा करते हैं।

विकल्प 2 थोड़ा बेहतर है, लेकिन ग्राहकों को प्रभावी रूप से एक-दूसरे को ओवरराइड करने की अनुमति देता है - यह सब कुछ लिखना बहुत आसान होगा। जो एक नया जोड़ने के बजाय किसी भी मौजूदा ईवेंट हैंडलर की जगह लेगा। इसके अलावा, आपको अभी भी गुण लिखने की आवश्यकता है।

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


अच्छा और संक्षिप्त विवरण। थैंक्स
पैप

यह किसी भी चीज़ से अधिक सैद्धांतिक चिंता का विषय है, लेकिन FWIW मुझे हमेशा "विकल्प 1 बुरा लगता है क्योंकि हम सार्वजनिक चर पसंद नहीं करते हैं" तर्क थोड़ा और स्पष्टीकरण का उपयोग कर सकता है। अगर वह कह रहा है कि क्योंकि यह "बुरा ओओपी अभ्यास" है, तो तकनीकी रूप से एक public Delegateचर "डेटा" को उजागर करेगा, लेकिन मेरे ज्ञान का सबसे अच्छा करने के लिए ओओपी ने कभी भी किसी अवधारणा का उल्लेख नहीं किया है जैसे कि Delegateयह एक "वस्तु" या "संदेश" नहीं है) , और .NET वास्तव में मुश्किल से डेटा की तरह प्रतिनिधियों का व्यवहार करता है।
जूनियर

हालाँकि मैं और अधिक व्यावहारिक सलाह देना चाहूँगा, यदि आप ऐसी स्थिति में हैं जहाँ आप यह सुनिश्चित करना चाहेंगे कि केवल एक हैंडलर है, तो वैरिएबल के AddXXXHandlerसाथ अपने तरीके बनाना private Delegateएक अच्छा विकल्प हो सकता है। इस मामले में आप यह देख सकते हैं कि क्या हैंडलर पहले से सेट है, और उचित रूप से प्रतिक्रिया करें। यह भी एक अच्छा सेटअप हो सकता है यदि आपको Delegateसभी हैंडलर को खाली करने में सक्षम होने के लिए ऑब्जेक्ट को रखने की आवश्यकता है ( eventआपको ऐसा करने का कोई तरीका नहीं देता है)।
जूनियर

7

नोट: यदि आपके पास C # 5.0 तक पहुंच है , तो दोनों के बीच के अंतरों को समझने के लिए "ईवेंट्स ऑफ प्लेज यूज ऑफ डेलिगेट्स" अध्याय 18 में "इवेंट्स" को पढ़ें।


यह हमेशा मुझे एक सरल, ठोस उदाहरण देने में मदद करता है। तो यहाँ समुदाय के लिए एक है। पहले मैं दिखाता हूं कि आप हमारे लिए ईवेंट्स का उपयोग करने के लिए अकेले प्रतिनिधियों का उपयोग कैसे कर सकते हैं। फिर मैं बताता हूं कि एक ही समाधान किस तरह के उदाहरण के साथ काम करेगा EventHandler। और फिर मैं समझाता हूं कि हम ऐसा क्यों करना चाहते हैं जो मैं पहले उदाहरण में समझाता हूं। यह पोस्ट जॉन स्कीट के एक लेख से प्रेरित थी ।

उदाहरण 1: सार्वजनिक प्रतिनिधि का उपयोग करना

मान लीजिए कि मेरे पास एक एकल ड्रॉप-डाउन बॉक्स के साथ एक WinForms ऐप है। ड्रॉप डाउन एक के लिए बाध्य है List<Person>। जहाँ व्यक्ति के पास Id, Name, NickName, HairColor के गुण हैं। मुख्य रूप पर एक कस्टम उपयोगकर्ता नियंत्रण है जो उस व्यक्ति के गुणों को दर्शाता है। जब कोई व्यक्ति चुने हुए व्यक्ति के गुणों को दिखाने के लिए उपयोगकर्ता नियंत्रण अद्यतन में ड्रॉप-डाउन में किसी व्यक्ति का चयन करता है।

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

यहाँ है कि कैसे काम करता है। हमारे पास तीन फाइलें हैं जो हमें इसे एक साथ रखने में मदद करती हैं:

  • Mediator.cs - स्थिर वर्ग प्रतिनिधियों को रखता है
  • Form1.cs - मुख्य रूप
  • DetailView.cs - उपयोगकर्ता नियंत्रण सभी विवरण दिखाता है

यहाँ प्रत्येक वर्ग के लिए प्रासंगिक कोड दिया गया है:

class Mediator
{
    public delegate void PersonChangedDelegate(Person p); //delegate type definition
    public static PersonChangedDelegate PersonChangedDel; //delegate instance. Detail view will "subscribe" to this.
    public static void OnPersonChanged(Person p) //Form1 will call this when the drop-down changes.
    {
        if (PersonChangedDel != null)
        {
            PersonChangedDel(p);
        }
    }
}

यहाँ हमारा उपयोगकर्ता नियंत्रण है:

public partial class DetailView : UserControl
{
    public DetailView()
    {
        InitializeComponent();
        Mediator.PersonChangedDel += DetailView_PersonChanged;
    }

    void DetailView_PersonChanged(Person p)
    {
        BindData(p);
    }

    public void BindData(Person p)
    {
        lblPersonHairColor.Text = p.HairColor;
        lblPersonId.Text = p.IdPerson.ToString();
        lblPersonName.Text = p.Name;
        lblPersonNickName.Text = p.NickName;

    }
}

अंत में हमारे Form1.cs में निम्न कोड है। यहां हम OnPersonChanged को कॉल कर रहे हैं, जो प्रतिनिधि को सब्सक्राइब किए गए किसी भी कोड को कॉल करता है।

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    Mediator.OnPersonChanged((Person)comboBox1.SelectedItem); //Call the mediator's OnPersonChanged method. This will in turn call all the methods assigned (i.e. subscribed to) to the delegate -- in this case `DetailView_PersonChanged`.
}

ठीक है। तो यह है कि आप घटनाओं का उपयोग किए बिना और केवल प्रतिनिधियों का उपयोग किए बिना यह काम कैसे प्राप्त करेंगे । हम सिर्फ एक सार्वजनिक प्रतिनिधि को एक वर्ग में रखते हैं - आप इसे स्थिर या एक सिंगलटन या जो कुछ भी बना सकते हैं। महान।

लेकिन, BUT, लेकिन, हम वही नहीं करना चाहते हैं जो मैंने अभी ऊपर वर्णित किया है। क्योंकि सार्वजनिक क्षेत्र कई, कई कारणों से खराब हैं । तो हमारे विकल्प क्या हैं? जैसा कि जॉन स्कीट बताते हैं, यहां हमारे विकल्प हैं:

  1. एक सार्वजनिक प्रतिनिधि चर (यह वही है जो हमने अभी ऊपर किया था। ऐसा मत करो। मैंने अभी आपको ऊपर बताया कि यह खराब क्यों है)
  2. एक प्रतिनिधि को एक सेट / सेट के साथ एक संपत्ति में डाल दें (यहां समस्या यह है कि ग्राहक एक-दूसरे को ओवरराइड कर सकते हैं - इसलिए हम प्रतिनिधि को तरीकों का एक समूह सदस्यता ले सकते हैं और फिर हम गलती PersonChangedDel = nullसे अन्य सभी सदस्यता को मिटा सकते हैं।) अन्य समस्या जो यहां बनी हुई है वह यह है कि चूंकि उपयोगकर्ताओं के पास प्रतिनिधि के पास पहुंच है, इसलिए वे मंगलाचरण सूची में लक्ष्यों को प्राप्त कर सकते हैं - हम नहीं चाहते कि बाहरी उपयोगकर्ता हमारे घटनाओं को बढ़ाएं।
  3. AddXXXHandler और RemoveXXXHandler विधियों के साथ एक प्रतिनिधि चर

यह तीसरा विकल्प अनिवार्य रूप से एक घटना है जो हमें देता है। जब हम एक EventHandler घोषित करते हैं, तो यह हमें एक प्रतिनिधि के लिए पहुंच प्रदान करता है - सार्वजनिक रूप से नहीं, एक संपत्ति के रूप में नहीं, लेकिन इस चीज के रूप में हम एक घटना को कहते हैं जिसमें एक्सेसर्स को सिर्फ जोड़ना / निकालना है।

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

उदाहरण 2: एक सार्वजनिक प्रतिनिधि के बजाय EventHandler के साथ

मध्यस्थ:

class Mediator
{

    private static readonly Mediator _Instance = new Mediator();

    private Mediator() { }

    public static Mediator GetInstance()
    {
        return _Instance;
    }

    public event EventHandler<PersonChangedEventArgs> PersonChanged; //this is just a property we expose to add items to the delegate.

    public void OnPersonChanged(object sender, Person p)
    {
        var personChangedDelegate = PersonChanged as EventHandler<PersonChangedEventArgs>;
        if (personChangedDelegate != null)
        {
            personChangedDelegate(sender, new PersonChangedEventArgs() { Person = p });
        }
    }
}

ध्यान दें कि यदि आप EventHandler पर F12 करते हैं, तो यह आपको दिखाएगा कि परिभाषा अतिरिक्त "प्रेषक" ऑब्जेक्ट के साथ एक सामान्य-ified प्रतिनिधि है:

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);

उपयोगकर्ता नियंत्रण:

public partial class DetailView : UserControl
{
    public DetailView()
    {
        InitializeComponent();
        Mediator.GetInstance().PersonChanged += DetailView_PersonChanged;
    }

    void DetailView_PersonChanged(object sender, PersonChangedEventArgs e)
    {
        BindData(e.Person);
    }

    public void BindData(Person p)
    {
        lblPersonHairColor.Text = p.HairColor;
        lblPersonId.Text = p.IdPerson.ToString();
        lblPersonName.Text = p.Name;
        lblPersonNickName.Text = p.NickName;

    }
}

अंत में, यहाँ Form1.cs कोड है:

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
        Mediator.GetInstance().OnPersonChanged(this, (Person)comboBox1.SelectedItem);
}

क्योंकि EventHandler चाहता है और EventArgs एक पैरामीटर के रूप में, मैंने इस वर्ग को सिर्फ एक संपत्ति के साथ बनाया है:

class PersonChangedEventArgs
{
    public Person Person { get; set; }
}

उम्मीद है कि आपको थोड़ा सा पता चलता है कि हमारे पास घटनाएँ क्यों हैं और वे कैसे भिन्न हैं - लेकिन कार्यात्मक रूप से समान हैं - प्रतिनिधियों के रूप में।


जबकि मैं इस पोस्ट में सभी अच्छे काम की सराहना करता हूं और मुझे इसमें सबसे ज्यादा पढ़ने में मजा आया, मुझे अभी भी लगता है कि एक मुद्दे पर ध्यान नहीं दिया जाता है The other problem that remains here is that since the users have access to the delegate, they can invoke the targets in the invocation list -- we don't want external users having access to when to raise our events। के नवीनतम संस्करण में Mediator, आप अभी भी कॉल कर सकते हैं OnPersonChangeजब भी आपके पास सिंगलटन का संदर्भ हो। शायद आपको यह उल्लेख करना चाहिए कि Mediatorदृष्टिकोण उस विशेष व्यवहार को नहीं रोकता है, और एक घटना बस के करीब है।
Ivaylo Slavov

6

आप इंटरफ़ेस घोषणाओं में घटनाओं का भी उपयोग कर सकते हैं, प्रतिनिधियों के लिए ऐसा नहीं है।


2
@surfen इंटरफ़ेस में ईवेंट हो सकते हैं, लेकिन प्रतिनिधि नहीं।
एलेक्जेंड्रा निकितिन

1
वास्तव में आप का अर्थ क्या है? आप Action a { get; set; }एक इंटरफ़ेस परिभाषा के अंदर हो सकते हैं ।
चायल दस ब्रिंक

6

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

समापन, हम निम्नलिखित अवलोकन कर सकते हैं : एक प्रतिनिधि द्वारा परिभाषित किया जाना चाहिए एक घटना के प्रकार । यह एक घटना और एक प्रतिनिधि के बीच मुख्य संबंध है और खंड II.18 में ECMA-335 (CLI) विभाजन I से VI तक की घटनाओं को परिभाषित करते हुए वर्णित है :

विशिष्ट उपयोग में, टाइपस्पीक (यदि मौजूद है) एक प्रतिनिधि को पहचानता है जिसके हस्ताक्षर घटना की अग्नि विधि में पारित तर्कों से मेल खाते हैं।

हालाँकि, इस तथ्य का यह मतलब नहीं है कि एक घटना एक बैकिंग प्रतिनिधि क्षेत्र का उपयोग करती है । सच में, एक घटना आपकी पसंद के किसी भी अलग डेटा संरचना के समर्थन क्षेत्र का उपयोग कर सकती है। यदि आप C # में किसी घटना को स्पष्ट रूप से कार्यान्वित करते हैं, तो आप ईवेंट हैंडलर को स्टोर करने के तरीके को चुनने के लिए स्वतंत्र हैं (ध्यान दें कि ईवेंट हैंडलर घटना के प्रकार के उदाहरण हैं , जो बदले में अनिवार्य रूप से एक प्रतिनिधि प्रकार है --- पिछले अवलोकन से --- )। लेकिन, आप उन ईवेंट हैंडलर (जो प्रतिनिधि उदाहरण हैं) को डेटा संरचना में संग्रहीत कर सकते हैं जैसे कि Listया एक Dictionaryया किसी अन्य या किसी बैकिंग प्रतिनिधि क्षेत्र में भी। लेकिन यह मत भूलो कि यह अनिवार्य नहीं है कि आप एक प्रतिनिधि क्षेत्र का उपयोग करें।


4

एक .net में एक घटना ऐड विधि और एक निकालें विधि का एक निर्दिष्ट संयोजन है, जिसमें दोनों कुछ विशेष प्रकार के प्रतिनिधि की अपेक्षा करते हैं। C # और vb.net दोनों ऐड और रिमूव तरीकों के लिए कोड को ऑटो-जनरेट कर सकते हैं, जो इवेंट सब्सक्रिप्शन को होल्ड करने के लिए एक प्रतिनिधि को परिभाषित करेगा, और उस सब्सक्रिप्शन डेलिगेट से / में डेलीगेट में पास / ऐड को हटा देगा। VB.net सदस्यता सूची के साथ स्वतः उत्पन्न कोड (RaiseEvent स्टेटमेंट के साथ) होगा यदि और केवल अगर यह गैर-रिक्त है; किसी कारण के लिए, सी # बाद उत्पन्न नहीं करता है।

ध्यान दें कि जबकि मल्टीकास्ट डेलीगेट का उपयोग करके इवेंट सब्सक्रिप्शन को प्रबंधित करना आम है, ऐसा करने का एकमात्र साधन नहीं है। सार्वजनिक दृष्टिकोण से, एक-टू-इवेंट ईवेंट सब्सक्राइबर को यह जानने की आवश्यकता है कि किसी ऑब्जेक्ट को यह कैसे पता होना चाहिए कि वह ईवेंट प्राप्त करना चाहता है, लेकिन यह जानने की आवश्यकता नहीं है कि ईवेंट को ऊपर उठाने के लिए प्रकाशक किस तंत्र का उपयोग करेगा। यह भी ध्यान दें कि जिसने भी .net में डेटा संरचना को परिभाषित किया है, उसने स्पष्ट रूप से सोचा था कि उन्हें बढ़ाने का एक सार्वजनिक साधन होना चाहिए, न तो C # और न ही vb.net उस सुविधा का उपयोग करता है।


3

सरल तरीके से घटना के बारे में परिभाषित करने के लिए:

घटना दो प्रतिबंधों के साथ एक प्रतिनिधि के लिए एक संदर्भ है

  1. सीधे आमंत्रित नहीं किया जा सकता
  2. सीधे मान निर्दिष्ट नहीं किए जा सकते हैं (उदाहरण के लिए eventObj = प्रतिनिधिमाथोड)

दो से ऊपर प्रतिनिधियों के लिए कमजोर बिंदु हैं और यह घटना में संबोधित किया गया है। फिडलर में अंतर दिखाने के लिए पूरा कोड नमूना यहाँ है https://dotnetfiddle.net/5iR3fB

ईवेंट और डेलिगेट और क्लाइंट कोड के बीच की टिप्पणी को टॉगल करें जो अंतर को समझने के लिए प्रतिनिधि को आमंत्रित / असाइन करता है

यहाँ इनलाइन कोड है।

 /*
This is working program in Visual Studio.  It is not running in fiddler because of infinite loop in code.
This code demonstrates the difference between event and delegate
        Event is an delegate reference with two restrictions for increased protection

            1. Cannot be invoked directly
            2. Cannot assign value to delegate reference directly

Toggle between Event vs Delegate in the code by commenting/un commenting the relevant lines
*/

public class RoomTemperatureController
{
    private int _roomTemperature = 25;//Default/Starting room Temperature
    private bool _isAirConditionTurnedOn = false;//Default AC is Off
    private bool _isHeatTurnedOn = false;//Default Heat is Off
    private bool _tempSimulator = false;
    public  delegate void OnRoomTemperatureChange(int roomTemperature); //OnRoomTemperatureChange is a type of Delegate (Check next line for proof)
    // public  OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above), 
    public  event OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above), 

    public RoomTemperatureController()
    {
        WhenRoomTemperatureChange += InternalRoomTemperatuerHandler;
    }
    private void InternalRoomTemperatuerHandler(int roomTemp)
    {
        System.Console.WriteLine("Internal Room Temperature Handler - Mandatory to handle/ Should not be removed by external consumer of ths class: Note, if it is delegate this can be removed, if event cannot be removed");
    }

    //User cannot directly asign values to delegate (e.g. roomTempControllerObj.OnRoomTemperatureChange = delegateMethod (System will throw error)
    public bool TurnRoomTeperatureSimulator
    {
        set
        {
            _tempSimulator = value;
            if (value)
            {
                SimulateRoomTemperature(); //Turn on Simulator              
            }
        }
        get { return _tempSimulator; }
    }
    public void TurnAirCondition(bool val)
    {
        _isAirConditionTurnedOn = val;
        _isHeatTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
        System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
        System.Console.WriteLine("Heat :" + _isHeatTurnedOn);

    }
    public void TurnHeat(bool val)
    {
        _isHeatTurnedOn = val;
        _isAirConditionTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
        System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
        System.Console.WriteLine("Heat :" + _isHeatTurnedOn);

    }

    public async void SimulateRoomTemperature()
    {
        while (_tempSimulator)
        {
            if (_isAirConditionTurnedOn)
                _roomTemperature--;//Decrease Room Temperature if AC is turned On
            if (_isHeatTurnedOn)
                _roomTemperature++;//Decrease Room Temperature if AC is turned On
            System.Console.WriteLine("Temperature :" + _roomTemperature);
            if (WhenRoomTemperatureChange != null)
                WhenRoomTemperatureChange(_roomTemperature);
            System.Threading.Thread.Sleep(500);//Every second Temperature changes based on AC/Heat Status
        }
    }

}

public class MySweetHome
{
    RoomTemperatureController roomController = null;
    public MySweetHome()
    {
        roomController = new RoomTemperatureController();
        roomController.WhenRoomTemperatureChange += TurnHeatOrACBasedOnTemp;
        //roomController.WhenRoomTemperatureChange = null; //Setting NULL to delegate reference is possible where as for Event it is not possible.
        //roomController.WhenRoomTemperatureChange.DynamicInvoke();//Dynamic Invoke is possible for Delgate and not possible with Event
        roomController.SimulateRoomTemperature();
        System.Threading.Thread.Sleep(5000);
        roomController.TurnAirCondition (true);
        roomController.TurnRoomTeperatureSimulator = true;

    }
    public void TurnHeatOrACBasedOnTemp(int temp)
    {
        if (temp >= 30)
            roomController.TurnAirCondition(true);
        if (temp <= 15)
            roomController.TurnHeat(true);

    }
    public static void Main(string []args)
    {
        MySweetHome home = new MySweetHome();
    }


}

2

डेलिगेट एक प्रकार-सुरक्षित फ़ंक्शन पॉइंटर है। ईवेंट प्रतिनिधि का उपयोग करके प्रकाशक-ग्राहक डिज़ाइन पैटर्न का कार्यान्वयन है।


0

यदि आप इंटरमीडिएट भाषा की जांच करते हैं, तो आपको पता चल जाएगा कि .net कंपाइलर IL में सीलबंद क्लास को कुछ बिल्ड-इन फंक्शंस के साथ इन्वॉल्व करता है, जैसे कि इनवोक, startInvoke, endInvoke और डेलीगेट क्लास दूसरी क्लास से विरासत में मिला है, जिसे शायद "SystemMulticast" कहा जाता है। मुझे लगता है कि इवेंट कुछ अतिरिक्त गुणों के साथ डेलिगेट का एक बच्चा वर्ग है।

घटना और प्रतिनिधि के बीच अंतर है, आप घोषणा के बाहर घटना नहीं चला सकते हैं। यदि आप कक्षा A में किसी घटना की घोषणा करते हैं, तो आप केवल कक्षा A में इस घटना को चला सकते हैं। यदि आप कक्षा A में एक प्रतिनिधि की घोषणा करते हैं, तो आप कहीं भी इस प्रतिनिधि का उपयोग कर सकते हैं। मुझे लगता है कि यह उनके बीच एक मुख्य अंतर है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.