.NET में घटना हस्ताक्षर - एक मजबूत टाइप 'प्रेषक' का उपयोग करना?


106

मुझे पूरी तरह से पता है कि मैं जो प्रस्ताव कर रहा हूं वह .NET दिशानिर्देशों का पालन नहीं करता है, और इसलिए, शायद अकेले इस कारण से एक खराब विचार है। हालांकि, मैं दो संभावित दृष्टिकोणों से इस पर विचार करना चाहूंगा:

(1) क्या मुझे अपने स्वयं के विकास कार्यों के लिए इसका उपयोग करने पर विचार करना चाहिए, जो आंतरिक उद्देश्यों के लिए 100% है।

(२) क्या यह एक अवधारणा है जिसे रूपरेखा डिजाइनर बदलने या अद्यतन करने पर विचार कर सकते हैं?

मैं एक घटना हस्ताक्षर का उपयोग करने के बारे में सोच रहा हूं जो एक मजबूत टाइप किए गए 'प्रेषक' का उपयोग करता है, इसके बजाय इसे 'ऑब्जेक्ट' के रूप में टाइप करना है, जो कि वर्तमान .NET डिज़ाइन पैटर्न है। इसके बजाय, मानक ईवेंट हस्ताक्षर का उपयोग करने के बजाय ऐसा दिखता है:

class Publisher
{
    public event EventHandler<PublisherEventArgs> SomeEvent;
}

मैं एक घटना हस्ताक्षर का उपयोग करने पर विचार कर रहा हूं जो एक मजबूत-टाइप किए गए 'प्रेषक' पैरामीटर का उपयोग करता है, इस प्रकार है:

सबसे पहले, एक "स्ट्रांगपाइपडेंटहैंडलर" परिभाषित करें:

[SerializableAttribute]
public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
    TSender sender,
    TEventArgs e
)
where TEventArgs : EventArgs;

यह सब एक एक्शन <TSender, TEventArgs> से अलग नहीं है, लेकिन इसका उपयोग करने से StrongTypedEventHandler, हम यह लागू करते हैं कि TEventArgs से व्युत्पन्न हैSystem.EventArgs

अगला, एक उदाहरण के रूप में, हम एक प्रकाशन वर्ग में StrongTypedEventHandler का उपयोग इस प्रकार कर सकते हैं:

class Publisher
{
    public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;

    protected void OnSomeEvent()
    {
        if (SomeEvent != null)
        {
            SomeEvent(this, new PublisherEventArgs(...));
        }
    }
}

उपरोक्त व्यवस्था ग्राहकों को एक मजबूत-टाइप ईवेंट हैंडलर का उपयोग करने में सक्षम बनाएगी जिसे कास्टिंग की आवश्यकता नहीं थी:

class Subscriber
{
    void SomeEventHandler(Publisher sender, PublisherEventArgs e)
    {           
        if (sender.Name == "John Smith")
        {
            // ...
        }
    }
}

मुझे पूरी तरह से एहसास है कि यह मानक .NET इवेंट-हैंडलिंग पैटर्न के साथ टूटता है; हालाँकि, इस बात का ध्यान रखें कि यदि वांछित हो तो एक ग्राहक एक पारंपरिक ईवेंट हैंडलिंग सिग्नेचर का उपयोग करने में सक्षम होगा:

class Subscriber
{
    void SomeEventHandler(object sender, PublisherEventArgs e)
    {           
        if (((Publisher)sender).Name == "John Smith")
        {
            // ...
        }
    }
}

यही है, अगर एक इवेंट हैंडलर को असमान (या शायद अज्ञात) ऑब्जेक्ट प्रकारों से घटनाओं की सदस्यता लेने की आवश्यकता होती है, तो संभावित प्रेषक ऑब्जेक्ट्स की पूरी चौड़ाई को संभालने के लिए हैंडलर 'प्रेषक' पैरामीटर को 'ऑब्जेक्ट' के रूप में टाइप कर सकता है।

ब्रेकिंग कन्वेंशन के अलावा (जो कुछ ऐसा है जिसे मैं हल्के में नहीं लेता हूं, मेरा विश्वास करो) मैं इसके लिए किसी भी डाउनडाइड के बारे में नहीं सोच सकता।

यहां कुछ सीएलएस अनुपालन मुद्दे हो सकते हैं। यह Visual Basic .NET 2008 100% ठीक है (मैंने परीक्षण किया है) में चलता है, लेकिन मेरा मानना ​​है कि 2005 के माध्यम से Visual Basic .NET के पुराने संस्करणों में प्रतिनिधि सहसंयोजक और विरोधाभासी नहीं है। [संपादित करें: मैंने इसका परीक्षण किया है, और इसकी पुष्टि की गई है: VB.NET 2005 और नीचे इसे संभाल नहीं सकता है, लेकिन VB.NET 2008 100% ठीक है। नीचे "संपादित करें # 2" देखें।] ऐसी अन्य .NET भाषाएँ हो सकती हैं, जिनके साथ भी यह समस्या है, मुझे यकीन नहीं हो रहा है।

लेकिन मैं अपने आप को C # या Visual Basic .NET के अलावा किसी भी भाषा के लिए विकसित नहीं देखता, और मुझे .NET फ्रेमवर्क 3.0 और इसके बाद के संस्करण के लिए इसे C # और VB.NET तक सीमित करने में कोई आपत्ति नहीं है। (मैं इस बिंदु पर 2.0 तक वापस जाने की कल्पना नहीं कर सकता था, ईमानदार होने के लिए।)

किसी और को इस के साथ एक समस्या के बारे में सोच सकते हैं? या यह केवल सम्मेलन के साथ इतना टूट जाता है कि यह लोगों के पेट को मोड़ देता है?

यहाँ कुछ संबंधित लिंक दिए गए हैं जिन्हें मैंने पाया है:

(1) इवेंट डिजाइन दिशानिर्देश [MSDN 3.5]

(2) C # सिंपल इवेंट राइज़िंग - "प्रेषक" बनाम कस्टम EventArgs का उपयोग करना [StackOverflow 2009]

(3) .net [StackOverflow 2008] में इवेंट सिग्नेचर पैटर्न

मुझे इस पर किसी की भी और सभी की राय में दिलचस्पी है ...

अग्रिम में धन्यवाद,

माइक

# 1 संपादित करें: यह टॉमी कार्लाइर की पोस्ट के जवाब में है :

यहां एक पूर्ण कार्य करने वाला उदाहरण दिखाया गया है कि मजबूत-टाइप किए गए ईवेंट हैंडलर और वर्तमान मानक ईवेंट हैंडलर दोनों एक 'ऑब्जेक्ट प्रेषक' पैरामीटर का उपयोग करते हैं जो इस दृष्टिकोण के साथ सह-अस्तित्व में हो सकते हैं। आप कोड में कॉपी-पेस्ट कर सकते हैं और उसे एक रन दे सकते हैं:

namespace csScrap.GenericEventHandling
{
    class PublisherEventArgs : EventArgs
    {
        // ...
    }

    [SerializableAttribute]
    public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
        TSender sender,
        TEventArgs e
    )
    where TEventArgs : EventArgs;

    class Publisher
    {
        public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;

        public void OnSomeEvent()
        {
            if (SomeEvent != null)
            {
                SomeEvent(this, new PublisherEventArgs());
            }
        }
    }

    class StrongTypedSubscriber
    {
        public void SomeEventHandler(Publisher sender, PublisherEventArgs e)
        {
            MessageBox.Show("StrongTypedSubscriber.SomeEventHandler called.");
        }
    }

    class TraditionalSubscriber
    {
        public void SomeEventHandler(object sender, PublisherEventArgs e)
        {
            MessageBox.Show("TraditionalSubscriber.SomeEventHandler called.");
        }
    }

    class Tester
    {
        public static void Main()
        {
            Publisher publisher = new Publisher();

            StrongTypedSubscriber strongTypedSubscriber = new StrongTypedSubscriber();
            TraditionalSubscriber traditionalSubscriber = new TraditionalSubscriber();

            publisher.SomeEvent += strongTypedSubscriber.SomeEventHandler;
            publisher.SomeEvent += traditionalSubscriber.SomeEventHandler;

            publisher.OnSomeEvent();
        }
    }
}

# 2 संपादित करें: यह एंड्रयू हारे के सहसंयोजक और विरोधाभासी के बयान के जवाब में है और यह यहां कैसे लागू होता है। C # भाषा में प्रतिनिधि इतने लंबे समय के लिए सहसंयोजक और विरोधाभासी रहे हैं कि यह सिर्फ "आंतरिक" लगता है, लेकिन ऐसा नहीं है। यह कुछ ऐसा भी हो सकता है जो सीएलआर में सक्षम है, मुझे नहीं पता, लेकिन विजुअल बेसिक .NET को अपने प्रतिनिधियों के लिए .NET फ्रेमवर्क 3.0 (VB.NET 2008) तक कोविरियस और कंट्रोवर्सी क्षमता नहीं मिली। और परिणामस्वरूप, .NET 2.0 और नीचे के लिए Visual Basic.NET इस दृष्टिकोण का उपयोग करने में सक्षम नहीं होगा।

उदाहरण के लिए, उपरोक्त उदाहरण VB.NET में अनुवादित किया जा सकता है:

Namespace GenericEventHandling
    Class PublisherEventArgs
        Inherits EventArgs
        ' ...
        ' ...
    End Class

    <SerializableAttribute()> _
    Public Delegate Sub StrongTypedEventHandler(Of TSender, TEventArgs As EventArgs) _
        (ByVal sender As TSender, ByVal e As TEventArgs)

    Class Publisher
        Public Event SomeEvent As StrongTypedEventHandler(Of Publisher, PublisherEventArgs)

        Public Sub OnSomeEvent()
            RaiseEvent SomeEvent(Me, New PublisherEventArgs)
        End Sub
    End Class

    Class StrongTypedSubscriber
        Public Sub SomeEventHandler(ByVal sender As Publisher, ByVal e As PublisherEventArgs)
            MessageBox.Show("StrongTypedSubscriber.SomeEventHandler called.")
        End Sub
    End Class

    Class TraditionalSubscriber
        Public Sub SomeEventHandler(ByVal sender As Object, ByVal e As PublisherEventArgs)
            MessageBox.Show("TraditionalSubscriber.SomeEventHandler called.")
        End Sub
    End Class

    Class Tester
        Public Shared Sub Main()
            Dim publisher As Publisher = New Publisher

            Dim strongTypedSubscriber As StrongTypedSubscriber = New StrongTypedSubscriber
            Dim traditionalSubscriber As TraditionalSubscriber = New TraditionalSubscriber

            AddHandler publisher.SomeEvent, AddressOf strongTypedSubscriber.SomeEventHandler
            AddHandler publisher.SomeEvent, AddressOf traditionalSubscriber.SomeEventHandler

            publisher.OnSomeEvent()
        End Sub
    End Class
End Namespace

VB.NET 2008 इसे 100% ठीक चला सकता है। लेकिन मैंने अब इसे VB.NET 2005 पर परीक्षण किया है, बस सुनिश्चित करने के लिए, और यह संकलित नहीं करता है:

विधि 'सार्वजनिक उप SomeEventHandler (प्रेषक ऑब्जेक्ट के रूप में, e as vGGenericEventHandling.GenericEventHandling.PublisherEventArgs)' के पास प्रतिनिधि के रूप में एक ही हस्ताक्षर नहीं है, जो 'डेलिगेट सब स्ट्रॉन्गटेडइवेंटहैंडलर (TSender, TEventArgs As System.EventAsgs' के रूप में है)। '

मूल रूप से, प्रतिनिधि VB.NET 2005 और उससे नीचे के संस्करणों में अपरिवर्तनीय हैं। मैं वास्तव में कुछ साल पहले इस विचार के बारे में सोचता था, लेकिन इस परेशान से निपटने के लिए VB.NET की अक्षमता ने मुझे परेशान कर दिया ... लेकिन मैंने अब C # को ठोस रूप से स्थानांतरित कर दिया है, और VB.NET अब इसे संभाल सकता है, इसलिए, अच्छी तरह से, इसलिए ये पद।

संपादित करें: # 3 अपडेट करें

ठीक है, मैं इसे थोड़ी देर के लिए सफलतापूर्वक उपयोग कर रहा हूं। यह वास्तव में एक अच्छी प्रणाली है। मैंने अपने "StrongTypedEventHandler" को "GenericEventHandler" के रूप में नामित करने का फैसला किया, इस प्रकार है:

[SerializableAttribute]
public delegate void GenericEventHandler<TSender, TEventArgs>(
    TSender sender,
    TEventArgs e
)
where TEventArgs : EventArgs;

इस नामकरण के अलावा, मैंने इसे ठीक उसी तरह लागू किया जैसा कि ऊपर चर्चा की गई है।

यह FxCop नियम CA1009 पर यात्रा करता है, जो बताता है:

"कन्वेंशन द्वारा, .NET इवेंट्स में दो पैरामीटर होते हैं जो ईवेंट भेजने वाले और ईवेंट डेटा को निर्दिष्ट करते हैं। ईवेंट हैंडलर सिग्नेचर को इस फॉर्म का पालन करना चाहिए: शून्य MyEventHandler (ऑब्जेक्ट प्रेषक, EventArgs e)। 'प्रेषक' पैरामीटर हमेशा System.Object का प्रकार होता है। भले ही यह अधिक विशिष्ट प्रकार को नियोजित करने के लिए संभव हो। 'e' पैरामीटर हमेशा प्रकार का System.EventArgs होता है। ईवेंट डेटा प्रदान नहीं करने वाली ईवेंट्स को System.EventHandler प्रतिनिधि प्रकार का उपयोग करना चाहिए। ईवेंट हैंडलर शून्य को वापस भेजते हैं जो वे भेज सकते हैं। प्रत्येक घटना कई लक्ष्य विधियों के लिए। किसी लक्ष्य द्वारा लौटाए गए मूल्य को पहली कॉल के बाद खो दिया जाएगा। "

बेशक, हम यह सब जानते हैं, और वैसे भी नियमों को तोड़ रहे हैं। (सभी ईवेंट हैंडलर किसी भी मामले में पसंद किए जाने पर अपने हस्ताक्षर में मानक 'ऑब्जेक्ट सेंडर' का उपयोग कर सकते हैं - यह एक गैर-परिवर्तनशील बदलाव है।)

तो SuppressMessageAttributeचाल का उपयोग करता है:

[SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly",
    Justification = "Using strong-typed GenericEventHandler<TSender, TEventArgs> event handler pattern.")]

मुझे उम्मीद है कि यह दृष्टिकोण भविष्य में किसी बिंदु पर मानक बन जाएगा। यह वास्तव में बहुत अच्छी तरह से काम करता है।

आपके सभी राय लोगों के लिए धन्यवाद, मैं वास्तव में इसकी सराहना करता हूं ...

माइक


6
कर दो। (ऐसा मत सोचो कि यह एक उत्तर को सही ठहराता है।)
कोनराड रूडोल्फ

1
मेरे तर्क वास्तव में आप पर इंगित नहीं किए गए थे: बेशक आपको अपनी परियोजनाओं में ऐसा करना चाहिए। वे तर्क थे कि यह बीसीएल में काम क्यों नहीं कर सकता है।
टॉमी कार्लाइल

3
यार, काश कि मेरा प्रोजेक्ट शुरू से ऐसा होता, मुझे भेजने वाले से नफरत है।
मैट एच।

7
अब यह एक सवाल है। देखें, दोस्तों? इनमें से एक भी ट्वीट के आकार का oh hi this my hom work solve it plz :code dump:सवाल नहीं है, लेकिन एक सवाल जो हम सीखते हैं
कैमिलो मार्टिन

3
एक और सुझाव, बस इसे नाम EventHandler<,>से GenericEventHandler<,>EventHandler<>बीसीएल में पहले से ही जेनेरिक है जिसे सिर्फ इवेंटहैंडलर नाम दिया गया है। तो EventHandler एक अधिक सामान्य नाम है और प्रतिनिधियों ने ओवरलोड का समर्थन किया है
nawfal

जवाबों:


25

ऐसा लगता है कि Microsoft ने इस पर उठाया है जैसा कि MSDN पर अब एक समान उदाहरण है:

जेनेरिक डेलीगेट्स


2
+1 आह, उत्कृष्ट। वे वास्तव में इस पर उठाया है। यह अच्छा है। मुझे उम्मीद है, हालांकि, कि वे इसे वीएस आईडीई के भीतर एक मान्यता प्राप्त पैटर्न बनाते हैं, क्योंकि, जैसा कि यह अब है, इंटेलीजेंसी, आदि के संदर्भ में इस पैटर्न का उपयोग करना अधिक अजीब है
माइक रोसेनब्लम

13

आप जो प्रस्ताव कर रहे हैं, वह वास्तव में समझ में आता है, और मुझे आश्चर्य होता है कि क्या यह उन चीजों में से एक है, जिस तरह से यह सिर्फ इसलिए है क्योंकि यह मूल रूप से जेनरिक से पहले डिज़ाइन किया गया था, या यदि इसके लिए एक वास्तविक कारण है।


1
मुझे यकीन है कि यह बिल्कुल कारण है। हालाँकि, अब जब भाषा के नए संस्करणों में इसे संभालने के लिए विरोधाभास है, तो ऐसा लग रहा है कि वे इसे पीछे से संगत तरीके से संभालने में सक्षम होना चाहिए। पिछले हैंडलर जो 'प्रेषक ऑब्जेक्ट' का उपयोग करते हैं, वे नहीं टूटेंगे। लेकिन यह पुरानी भाषाओं के लिए सच नहीं है और कुछ मौजूदा .NET भाषाओं के लिए सच नहीं हो सकता है, मुझे यकीन नहीं है।
माइक रोसेनब्लम

13

विंडोज रनटाइम (WinRT) एक TypedEventHandler<TSender, TResult>प्रतिनिधि का परिचय देता है , जो आपके कार्य StrongTypedEventHandler<TSender, TResult>को ठीक करता है, लेकिन जाहिर तौर पर TResultटाइप पैरामीटर पर बाधा के बिना :

public delegate void TypedEventHandler<TSender, TResult>(TSender sender,
                                                         TResult args);

MSDN प्रलेखन यहाँ है


1
आह, यह देखकर अच्छा लगा कि प्रगति है ... मुझे आश्चर्य है कि 'इवेंटअग्र्स' वर्ग से ट्राइसेल को विरासत में प्रतिबंधित क्यों नहीं किया गया है। 'EventArgs' का आधार वर्ग आधारभूत रूप से खाली है; शायद वे इस प्रतिबंध से दूर जा रहे हैं?
माइक रोसेनब्लम

यह डिजाइन टीम का निरीक्षण हो सकता है; कौन जानता है।
पियरे अरनौद

अच्छी तरह से, घटनाओं का उपयोग किए बिना ठीक काम करते हैं EventArgs, यह सिर्फ एक सम्मेलन की चीज है
सेबस्टियन

3
यह विशेष रूप से TypedEventHandler दस्तावेज में कहा गया है कि argsहो जाएगा nullअगर कोई घटना डेटा है, इसलिए यह प्रकट होता है कि वे डिफ़ॉल्ट रूप से अनिवार्य रूप से एक खाली वस्तु का उपयोग करने से दूर हो रही है। मैं अनुमान लगा रहा हूं कि मूल विचार यह था कि प्रकार के दूसरे पैरामीटर के साथ एक विधि EventArgsकिसी भी घटना को संभाल सकती है क्योंकि प्रकार हमेशा संगत होंगे। वे शायद अब महसूस कर रहे हैं कि एक विधि के साथ कई अलग-अलग घटनाओं को संभालने में सक्षम होना महत्वपूर्ण नहीं है।
jmcilhinney

1
यह एक निरीक्षण की तरह नहीं दिखता है। बाधा को System.EventHandler <TEventArgs> प्रतिनिधि के रूप में भी हटा दिया गया था। referenceource.microsoft.com/#mscorlib/system/…
colton7909

5

मैं निम्नलिखित बयानों के साथ समस्या लेता हूं:

  • मेरा मानना ​​है कि 2005 के माध्यम से Visual Basic .NET के पुराने संस्करणों में प्रतिनिधि सहसंयोजक और विरोधाभासी नहीं है।
  • मुझे पूरी तरह से एहसास है कि यह निन्दा पर कगार है।

सबसे पहले, आपने यहां कुछ भी नहीं किया है जिसका कोविरेंस या कंट्रोवर्सी से कोई लेना-देना नहीं है। ( संपादित करें: पिछला विवरण गलत है, अधिक जानकारी के लिए कृपया कॉलेरिएनस और कंट्रावेरियन्स इन डेलिगेट्स देखें ) यह समाधान सभी सीएलआर संस्करणों 2.0 और ऊपर में ठीक काम करेगा (जाहिर है कि यह सीएलआर 1.0 आवेदन में काम नहीं करेगा क्योंकि यह जेनरिक है)।

दूसरे, मैं दृढ़ता से असहमत हूं कि आपका विचार "निन्दा" पर आधारित है क्योंकि यह एक अद्भुत विचार है।


2
हाय एंड्रयू, अंगूठे के लिए धन्यवाद! आपकी प्रतिष्ठा के स्तर को देखते हुए, यह वास्तव में मेरे लिए बहुत मायने रखता है ... सहसंयोजक / विरोधाभासी मुद्दे पर: यदि ग्राहक द्वारा प्रदान किया गया प्रतिनिधि प्रकाशक के घटना के हस्ताक्षर से बिल्कुल मेल नहीं खाता है, तो सहसंयोजक और विरोधाभासी शामिल हैं। C # में हमेशा से ही सहसंयोजक और विरोधाभासी प्रतिनिधि रहे हैं, इसलिए यह आंतरिक लगता है, लेकिन VB.NET के पास .NET 3.0 तक सहसंयोजक और विरोधाभासी प्रतिनिधि नहीं थे। इसलिए, .NET 2.0 और नीचे के लिए VB.NET इस प्रणाली का उपयोग नहीं कर पाएंगे। (ऊपर "एडिट # 2" में जोड़ा गया कोड उदाहरण देखें।)
माइक रोसेनब्लम

@ माइक - मेरी क्षमायाचना, आप 100% सही हैं! मैंने आपकी बात को प्रतिबिंबित करने के लिए अपना उत्तर संपादित किया है :)
एंड्रयू हरे

4
आह, दिलचस्प! ऐसा लगता है कि प्रतिनिधि सहसंयोजक / विरोधाभासी सीएलआर का हिस्सा है, लेकिन (उन कारणों के लिए जो मुझे नहीं पता) यह सबसे हाल के संस्करण से पहले VB.NET द्वारा उजागर नहीं किया गया था। यहाँ फ्रांसेस्को बलेना का एक लेख है जिसमें दिखाया गया है कि कैसे प्रतिनिधि विचलन का उपयोग कर प्राप्त किया जा सकता है, यदि भाषा स्वयं सक्षम नहीं है: dotnet2themax.com/blogs/fbalena/…
माइक रोसेनब्लम

1
@ माइक - यह हमेशा उन चीजों को सीखने के लिए दिलचस्प है जो सीएलआर अभी तक समर्थन नहीं करती हैं। .NET भाषाओं में से किसी में भी समर्थित नहीं हैं।
एंड्रयू हरे

5

मैंने इस बात पर एक नज़र डाली कि इसे नए WinRT के साथ कैसे संभाला गया और यहाँ अन्य राय के आधार पर, और आखिरकार इसे इस तरह करने पर बस गया:

[Serializable]
public delegate void TypedEventHandler<in TSender, in TEventArgs>(
    TSender sender,
    TEventArgs e
) where TEventArgs : EventArgs;

यह WinRT में TypedEventHandler नाम के उपयोग को देखते हुए सबसे अच्छा तरीका है।


TEventArgs पर सामान्य प्रतिबंध क्यों जोड़ें? यह EventHandler <> और TypedEventHandler <,> से हटा दिया गया था क्योंकि यह वास्तव में कोई मतलब नहीं था।
माइक मैरीनोव्स्की

2

मुझे लगता है कि यह एक महान विचार है और एमएस के पास शायद इस समय को बेहतर बनाने के लिए निवेश करने का समय या रुचि नहीं है, उदाहरण के लिए जब वे ArrayList से जेनेरिक आधारित सूचियों में चले गए।


आप सही हो सकते हैं ... दूसरी तरफ, मुझे लगता है कि यह सिर्फ एक "मानक" है, और संभवत: एक तकनीकी मुद्दा नहीं है। अर्थात्, यह क्षमता सभी वर्तमान .NET भाषाओं में मौजूद हो सकती है, मुझे नहीं पता। मुझे पता है कि C # और VB.NET इसे संभाल सकते हैं। हालाँकि, मुझे यकीन नहीं है कि यह सभी मौजूदा .NET भाषाओं में व्यापक रूप से कैसे काम करता है ... लेकिन चूंकि यह C # और VB.NET में काम करता है, और यहाँ हर कोई इतना सहायक है, मुझे लगता है कि मुझे ऐसा करने की बहुत संभावना है। :-)
माइक रोसेनब्लम

2

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

चूंकि यह संभव है कि कोई वस्तु किसी अन्य वस्तु की ओर से घटनाओं को भेज सकती है, इसलिए मैं "प्रेषक" फ़ील्ड के लिए कुछ संभावित उपयोगिता देख सकता हूं जो ऑब्जेक्ट प्रकार का है, और EventArgs-व्युत्पन्न फ़ील्ड के लिए ऑब्जेक्ट का संदर्भ होना चाहिए पर कार्रवाई की जाए। "प्रेषक" फ़ील्ड की उपयोगिता, हालांकि, शायद इस तथ्य से सीमित है कि किसी अज्ञात प्रेषक से किसी वस्तु को अनसब्सक्राइब करने का कोई साफ तरीका नहीं है।

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


2

ई-मेल भेजने वाले के लिए एकमात्र कारण के रूप में ईश निंदा को देखते हुए (यदि वीबी 2005 कोड में विरोधाभासी समस्याओं को दूर करना है, जो कि माइक्रोसॉफ्ट का ब्लंडर आईएमएचओ है), तो कोई भी व्यक्ति दूसरे तर्क को EventArgs टाइप करने के लिए कम से कम सैद्धांतिक मकसद सुझा सकता है। इससे भी आगे जाते हुए, क्या इस विशेष मामले में Microsoft के दिशानिर्देशों और सम्मेलनों के अनुरूप होने का एक अच्छा कारण है?

एक और डेटा के लिए एक और EventArgs आवरण विकसित करने की आवश्यकता है, जिसे हम ईवेंट हैंडलर के अंदर से गुजरना चाहते हैं, यह अजीब लगता है, क्यों सीधे उस डेटा को वहां से पारित नहीं किया जा सकता है। कोड के निम्नलिखित वर्गों पर विचार करें

[उदाहरण 1]

public delegate void ConnectionEventHandler(Server sender, Connection connection);

public partial class Server
{
    protected virtual void OnClientConnected(Connection connection)
    {
        if (ClientConnected != null) ClientConnected(this, connection);
    }

    public event ConnectionEventHandler ClientConnected;
}

[उदाहरण २]

public delegate void ConnectionEventHandler(object sender, ConnectionEventArgs e);

public class ConnectionEventArgs : EventArgs
{
    public Connection Connection { get; private set; }

    public ConnectionEventArgs(Connection connection)
    {
        this.Connection = connection;
    }
}

public partial class Server
{
    protected virtual void OnClientConnected(Connection connection)
    {
        if (ClientConnected != null) ClientConnected(this, new ConnectionEventArgs(connection));
    }

    public event ConnectionEventHandler ClientConnected;
}

2
हां, System.EventArgs से विरासत में मिला एक अलग वर्ग बनाना अनपेक्षित लग सकता है और अतिरिक्त कार्य का प्रतिनिधित्व करता है, लेकिन इसके लिए एक बहुत अच्छा कारण है। यदि आपको अपना कोड बदलने की आवश्यकता नहीं है, तो आपका दृष्टिकोण ठीक है। लेकिन वास्तविकता यह है कि आपको भविष्य के संस्करण में ईवेंट की कार्यक्षमता बढ़ाने और इवेंट आर्गन में गुण जोड़ने की आवश्यकता हो सकती है। अपने परिदृश्य में, आपको इवेंट हैंडलर के हस्ताक्षर में अतिरिक्त अधिभार या वैकल्पिक पैरामीटर जोड़ना होगा। यह वीबीए और विरासत वीबी 6.0 में उपयोग किया जाने वाला एक दृष्टिकोण है, जो व्यावहारिक है, लेकिन व्यवहार में थोड़ा बदसूरत है।
माइक रोसेनब्लम

1
EventArgs से विरासत में, हालाँकि, एक भविष्य का संस्करण आपके पुराने ईवेंट तर्क वर्ग से इनहेरिट कर सकता है और इसे संवर्धित कर सकता है। सभी पुराने कॉलर अभी भी ठीक उसी तरह से काम कर सकते हैं, जैसे आपके नए ईवेंट तर्क वर्ग के आधार वर्ग के विरुद्ध काम करके। बहुत साफ। आपके लिए अधिक काम, लेकिन किसी भी कॉलर्स के लिए क्लीनर जो आपके पुस्तकालय पर निर्भर करता है।
23:30 पर माइक रोसेनब्लम

इसे विरासत में देने की भी आवश्यकता नहीं है, आप केवल अतिरिक्त कार्यक्षमता को सीधे अपने इवेंट args वर्ग में जोड़ सकते हैं और यह ठीक काम करना जारी रखेगा। उस ने कहा, Eventargs पर प्रतिबंध लगाने का तर्क दिया गया था क्योंकि यह बहुत सारे परिदृश्यों के लिए बहुत मायने नहीं रखता था, अर्थात। जब आप जानते हैं कि आपको किसी विशेष घटना की कार्यक्षमता का विस्तार करने की आवश्यकता नहीं होगी या जब आप सभी की आवश्यकता होती है तो बहुत ही संवेदनशील संवेदनशील अनुप्रयोगों में एक मूल्य प्रकार arg होता है।
माइक मैरीनोव्स्की

1

वर्तमान स्थिति (प्रेषक वस्तु है) के साथ, आप आसानी से कई घटनाओं के लिए एक विधि संलग्न कर सकते हैं:

button.Click += ClickHandler;
label.Click += ClickHandler;

void ClickHandler(object sender, EventArgs e) { ... }

यदि प्रेषक सामान्य होगा, तो क्लिक-ईवेंट का लक्ष्य टाइप बटन या लेबल का नहीं होगा, बल्कि टाइप कंट्रोल का होगा (क्योंकि घटना नियंत्रण पर परिभाषित है)। तो बटन-क्लास की कुछ घटनाओं में एक प्रकार का नियंत्रण होगा, अन्य में अन्य लक्ष्य प्रकार होंगे।


2
टॉमी, आप सिस्टम के साथ ठीक यही काम कर सकते हैं जो मैं प्रस्तावित कर रहा हूं। आप अभी भी एक मानक ईवेंट हैंडलर का उपयोग कर सकते हैं जिसमें इन मजबूत-टाइप किए गए ईवेंट्स को संभालने के लिए 'ऑब्जेक्ट प्रेषक' पैरामीटर है। (कोड उदाहरण देखें जो मैंने अब मूल पोस्ट में जोड़ दिया है।)
माइक रोसेनब्लम

हाँ, मैं मानता हूँ, यह मानक .NET इवेंट्स के बारे में अच्छी बात है, स्वीकृत है!
Lu4

1

मुझे नहीं लगता कि आप जो करना चाहते हैं उसमें कुछ गड़बड़ है। अधिकांश भाग के लिए, मुझे संदेह है कि object senderपूर्व 2.0 कोड का समर्थन जारी रखने के लिए पैरामीटर बना हुआ है।

यदि आप वास्तव में सार्वजनिक API के लिए यह परिवर्तन करना चाहते हैं, तो आप अपना आधार EvenArgs वर्ग बनाने पर विचार कर सकते हैं। कुछ इस तरह:

public class DataEventArgs<TSender, TData> : EventArgs
{
    private readonly TSender sender, TData data;

    public DataEventArgs(TSender sender, TData data)
    {
        this.sender = sender;
        this.data = data;
    }

    public TSender Sender { get { return sender; } }
    public TData Data { get { return data; } }
}

तब आप अपनी घटनाओं को इस तरह घोषित कर सकते हैं

public event EventHandler<DataEventArgs<MyClass, int>> SomeIndexSelected;

और इस तरह के तरीके:

private void HandleSomething(object sender, EventArgs e)

अभी भी सदस्यता ले पाएंगे।

संपादित करें

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

इसके साथ चिपके रहने का एक लाभ यह DataEventArgsहै कि आप ईवेंट को चेन कर सकते हैं, जिससे प्रेषक को बदल सकते हैं (अंतिम प्रेषक का प्रतिनिधित्व करने के लिए) जबकि EventArgs मूल प्रेषक को बनाए रखता है।


हे माइकल, यह एक बहुत साफ विकल्प है। मुझें यह पसंद है। जैसा कि आप उल्लेख करते हैं, हालांकि, 'प्रेषक' पैरामीटर को प्रभावी रूप से दो बार में पारित करना निरर्थक है। इसी तरह के दृष्टिकोण पर यहां चर्चा की गई है: stackoverflow.com/questions/809609/… , और सर्वसम्मति से लगता है कि यह बहुत गैर-मानक है। यही कारण है कि मैं यहां मजबूत-टाइप 'प्रेषक' विचार का सुझाव देने में संकोच कर रहा था। (लगता है कि अच्छी तरह से प्राप्त किया जा सकता है, इसलिए मैं प्रसन्न हूँ।)
माइक रोसेनब्लम

1

इसका लाभ उठाएं। नॉन कंपोनेंट आधारित कोड के लिए, मैं अक्सर इवेंट सिग्नेचर को सिंपल होने के लिए सरल बनाता हूं

public event Action<MyEventType> EventName

जहां MyEventTypeसे विरासत में नहीं मिलता है EventArgs। परेशान क्यों, अगर मैं EventArgs के किसी भी सदस्य का उपयोग करने का इरादा नहीं है।


1
इस बात से सहमत! हमें खुद को बंदर क्यों महसूस करना चाहिए?
Lu4

1
+ 1-ed, यह वही है जो मैं भी उपयोग करता हूं। कभी-कभी सादगी जीत जाती है! या यहां तक ​​कि event Action<S, T>, event Action<R, S, T>आदि मेरे पास Raiseउनके लिए एक विस्तार विधि है धागा-सुरक्षित रूप से :)
nawfal
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.