ReSharper / C # में "प्रतिनिधि घटाव का अप्रत्याशित परिणाम है"?


124

जब myDelegate -= eventHandlerReSharper (6 संस्करण) मुद्दों का उपयोग कर :

प्रतिनिधि घटाव अप्रत्याशित परिणाम है

इसके पीछे के तर्क को यहाँ JetBrains द्वारा समझाया गया है । स्पष्टीकरण समझ में आता है और इसे पढ़ने के बाद, मैं -प्रतिनिधियों पर अपने सभी उपयोगों पर संदेह कर रहा हूं ।

फिर कैसे ,

  • क्या मैं ReSharper को क्रोधी बनाए बिना एक गैर-ऑटो घटना लिख ​​सकता हूं?
  • या, क्या इसे लागू करने का एक बेहतर और / या "सही" तरीका है?
  • या, मैं सिर्फ ReSharper को नजरअंदाज कर सकता हूं?

यहाँ सरल कोड है:

public delegate void MyHandler (object sender);

MyHandler _myEvent;

public event MyHandler MyEvent
{
    add
    {
        _myEvent += value;
        DoSomethingElse();
    }
    remove
    {
        _myEvent -= value; // <-- ReSharper warning here
    }
}

मोनो वही चेतावनी देता है। यहाँ आर # की समस्या का विवरण है confluence.jetbrains.com/display/ReSharper/... (जो केवल प्रतिनिधियों की सूचियों पर लागू)
thoredge

जवाबों:


134

डरो मत! ReSharper की चेतावनी का पहला भाग केवल प्रतिनिधियों की सूची को हटाने के लिए लागू होता है। आपके कोड में, आप हमेशा एक प्रतिनिधि को निकाल रहे हैं। दूसरा भाग डुप्लिकेट प्रतिनिधि को हटाए जाने के बाद प्रतिनिधियों के आदेश के बारे में बात करता है। एक घटना अपने ग्राहकों के लिए निष्पादन के आदेश की गारंटी नहीं देती है, इसलिए यह वास्तव में आपको प्रभावित नहीं करती है।

चूंकि उपर्युक्त यांत्रिकी अप्रत्याशित परिणाम दे सकते हैं, ReSharper एक चेतावनी जारी करता है जब भी यह एक प्रतिनिधि उप-संचालक ऑपरेटर से सामना करता है।

ReSharper इस चेतावनी को जारी कर रहा है क्योंकि मल्टीकास्ट प्रतिनिधि घटाव में गोच हो सकता है, यह पूरी तरह से उस भाषा सुविधा की निंदा नहीं कर रहा है। सौभाग्य से वे गोटिंग्स फ्रिंज मामलों में हैं और अगर आप सिर्फ साधारण घटनाओं को साध रहे हैं, तो उनका सामना करने की संभावना नहीं है। अपने स्वयं के कार्यान्वयन के लिए कोई बेहतर तरीका नहीं हैadd / removeहैंडलर , आप सिर्फ नोटिस ले सकते हैं।

मैं उस संदेश के लिए "हिंट" के लिए ReSharper के चेतावनी स्तर को अपग्रेड करने का सुझाव दूंगा ताकि आप उनकी चेतावनियों के प्रति निराश न हों, जो आमतौर पर उपयोगी होते हैं।


66
मुझे लगता है कि परिणामों को "अप्रत्याशित" कहने के लिए आर # का बुरा है। वे बहुत स्पष्ट रूप से निर्दिष्ट हैं। "उपयोगकर्ता क्या भविष्यवाणी कर सकता है" किसी भी तरह से "अप्रत्याशित" के समान नहीं है। (यह कहना भी गलत है कि .NET फ्रेमवर्क ओवरलोड्स को परिभाषित करता है - यह C # कंपाइलर में बेक किया गया है। ओवरलोड नहींDelegate करता है और )।+-
जॉन स्कीट

6
@ जॉन: मैं सहमत हूं। मुझे लगता है कि हर किसी को अपने लिए उच्च बार Microsoft सेट की आदत हो गई है। पॉलिश का स्तर जितना ऊँचा होता है। .NET दुनिया की बहुत सी चीजों के साथ जो आपको "सफलता के गर्त में गिरा देती हैं", एक भाषा सुविधा का सामना करती है, जो उस गड्ढे के बगल में एक तेज चलना है जहाँ पर एक है मौका है कि आप याद कर सकते हैं यह कुछ लोगों द्वारा किया जा रहा है और एक संकेत कह वारंट है PIT OF SUCCESS IS THAT WAY --->
एलन ग्रेलनेक

5
@AllonGuralnek: दूसरी ओर, जब आखिरी बार आपने किसी को वास्तव में इस वजह से समस्या होने के बारे में सुना था?
जॉन स्कीट

5
@ जॉन: इसके साथ एक समस्या के बारे में सुना है? इस प्रश्न के पोस्ट होने से पहले मुझे इस व्यवहार के बारे में पता नहीं था।
एलन ग्रेलनेक

2
यह उत्सुक है कि आर # प्रतिनिधि घटाव के बारे में चेतावनी देगा, लेकिन उन घटनाओं के सामान्य कार्यान्वयन के बारे में चेतावनी नहीं देगा जिनके पास एक ही मुद्दा है । मुख्य समस्या यह है कि .net एक एकल का उपयोग करता है Delegate.Combineजो "मल्टीटास्ट" को समतल करता है , इसलिए यदि इसे प्रतिनिधियों [X, Y] और Z को दिया जाता है, तो यह नहीं बता सकता है कि परिणाम [X, Y, Z] या [होना चाहिए] X, Y], Z] (बाद वाले [X,Y]डेलीगेट को अपने डेलीगेट के रूप में Target, और उस डेलीगेट के Invokeतरीके को Method)।
सुपरकैट

28

योग या घटाना करने के लिए आपको सीधे प्रतिनिधियों का उपयोग नहीं करना चाहिए। इसके बजाय अपने क्षेत्र

MyHandler _myEvent;

इसके बजाय एक घटना के रूप में भी घोषित किया जाना चाहिए। यह आपके समाधान को जोखिम में डाले बिना समस्या को हल करेगा और अभी भी घटना के उपयोग का लाभ होगा।

event MyHandler _myEvent;

डेलीगेट योग या घटाना का उपयोग खतरनाक है क्योंकि आप घटनाओं को खो सकते हैं जब बस प्रतिनिधि को सौंपते हैं (घोषणा के अनुसार, डेवलपर सीधे अनुमान नहीं लगाएगा कि यह एक मल्टीकास्ट प्रतिनिधि है जब इसे एक घटना के रूप में घोषित किया जाता है)। केवल उदाहरण के लिए, यदि इस प्रश्न पर उल्लिखित संपत्ति को एक घटना के रूप में चिह्नित नहीं किया गया था, तो नीचे दिए गए कोड में दो पहले असाइनमेंट LOST होंगे, क्योंकि किसी को केवल प्रतिनिधि को सौंपा गया है (जो कि वैध भी है!)।

myObject.MyEvent += Method1; 
myObject.MyEvent += Method2;
myObject.MyEvent = Method3;

Method3 असाइन करते समय, मैंने दो प्रारंभिक सदस्यताएँ पूरी तरह से खो दी हैं। ईवेंट उपयोग इस समस्या से बचाएगा और उसी समय रीशर चेतावनी को हटा दें।


मैंने इसे इस तरह से करने के बारे में कभी नहीं सोचा था, लेकिन जब तक आप उस अंतर्निहित घटना को निजी रखते हैं, तब तक इवेंट प्रतिनिधि के उपयोग की रक्षा करने का कोई मतलब नहीं है। हालाँकि यह अधिक अच्छी तरह से काम नहीं करता है जब अधिक विशिष्ट थ्रेड सिंक्रोनाइज़ेशन होते हैं जो ऐड / रिमूव हैंडलर जैसे कि कई ईवेंट सब्सक्रिप्शन या सब-सब्सक्रिप्शन में होते हैं जिन्हें ट्रैक करने की आवश्यकता होती है। हालांकि, किसी भी मामले में यह चेतावनी को हटा देता है।
जेरेमी

-17

उपयोग करने के बजाय इसे = null पर सेट करें - =


5
removeकिसी ईवेंट की विधि को सभी हैंडलर को नहीं निकालना चाहिए, बल्कि उस हैंडलर को हटाने का अनुरोध करना चाहिए।
17

यदि वह केवल एक जोड़ा है तो यदि वह केवल एक को हटाता है तो वह उन सभी को हटा देता है। मैं यह नहीं कह रहा हूँ कि यह सभी मामलों में इस विशिष्ट पुनर्जीवन संदेश के लिए उपयोग करें।
जोनाथन बेर्स्फोर्ड

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

मुझे इसे आगे बढ़ाना पड़ा क्योंकि -17 किसी को "संभावित" उत्तर लिखने के लिए समय लेने के लिए एक दंड का बहुत कठोर है। +1 निष्क्रिय न होने के लिए, भले ही आप गलत थे।
जॉन सी।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.