2012-03-23 12 views
8

सी # हमें to create custom event accessors की अनुमति देता है।क्या एक कंपाइलर जेनरेटेड ईवेंट का बैकिंग फ़ील्ड हमेशा ईवेंट के समान नाम का उपयोग करने की गारंटी देता है?

Action _custom; 
public event Action Custom 
{ 
    add { _custom = (Action)Delegate.Combine(_custom, value); } 
    remove { _custom = (Action)Delegate.Remove(_custom, value); } 
} 

आप उन्हें निर्दिष्ट नहीं करते हैं, the compiler creates them for you। सी # भाषा कल्पना:

जब एक क्षेत्र की तरह घटना संकलन, संकलक स्वचालित रूप से भंडारण प्रतिनिधि धारण करने के लिए बनाता है, और घटना है कि जोड़ सकते हैं या प्रतिनिधि क्षेत्र के लिए ईवेंट हैंडलर्स हटाने के लिए accessors पैदा करता है।

decompiled स्रोत एक सरल public event Action Public; के लिए dotPeek का उपयोग कर कोड इस प्रकार दिखता है:

private Action Public; 

    public event Action Public 
    { 
    add 
    { 
     Action action = this.Public; 
     Action comparand; 
     do 
     { 
     comparand = action; 
     action = Interlocked.CompareExchange<Action>(
        ref this.Public, comparand + value, comparand); 
     } 
     while (action != comparand); 
    } 
    remove 
    { 
     Action action = this.Public; 
     Action comparand; 
     do 
     { 
     comparand = action; 
     action = Interlocked.CompareExchange<Action>(
        ref this.Public, comparand - value, comparand); 
     } 
     while (action != comparand); 
    } 
    } 

उल्लेखनीय है कि क्षेत्र और घटना में एक ही नाम का उपयोग करें। इसने निष्कर्ष निकालने के लिए some people का नेतृत्व किया है कि आप कक्षा में फ़ील्ड को ईवेंट के समान नाम से देखकर प्रतिबिंब के दौरान बैकिंग फ़ील्ड के बारे में जानकारी प्राप्त कर सकते हैं।

public static FieldInfo GetFieldInfo(this EventInfo eventInfo) 
{ 
    Contract.Requires(eventInfo != null); 

    return eventInfo.DeclaringType.GetField(
     eventInfo.Name, 
     BindingFlags.DeclaredOnly | BindingFlags.Instance | 
      BindingFlags.Public | BindingFlags.NonPublic); 
} 

यह काम करता है, लेकिन सवाल उठता है: एक संकलक उत्पन्न घटना हमेशा घटना के रूप में समान नाम का उपयोग करने की गारंटी के समर्थन क्षेत्र है इस प्रकार मैं इस कार्यान्वित?

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

उत्तर

9

क्या एक कंपाइलर जेनरेटेड ईवेंट का बैकिंग फ़ील्ड हमेशा ईवेंट के समान नाम का उपयोग करने की गारंटी देता है?

जॉन और मार्क पूरी तरह उत्तर देने के लिए सही हैं "नहीं"।

यह संकलक का एक अनियंत्रित कार्यान्वयन विवरण है, स्पष्ट रूप से विनिर्देश द्वारा नोट किया गया है, और किसी भी समय परिवर्तन के अधीन है।

प्रैक्टिस में, यह बदलने की संभावना नहीं है। हम इस तथ्य का उपयोग करते हैं कि क्षेत्र और घटना के समान नाम है जो उन्हें संकलक में एक-दूसरे के साथ तर्कसंगत रूप से जोड़ने के लिए सबसे आसान तरीका है।

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

सही।

मुझे आश्चर्य है कि आप यह निष्कर्ष निकाल सकते हैं कि कोई भी घटना जिसके लिए एक ही नाम के साथ कोई समर्थन प्रतिनिधि उपलब्ध नहीं है, वह कस्टम एक्सेसर्स के साथ एक कार्यक्रम है।

मैं इस तरह के निष्कर्ष को सहज महसूस नहीं कर पाऊंगा। यदि आप जानते थे कि प्रश्न में असेंबली सी # कंपाइलर से निकल गई है तो आप यह निष्कर्ष निकालने में सक्षम हो सकते हैं। लेकिन जब हम असेंबली उत्सर्जित करने की बात आती है तो हम शहर में एकमात्र खेल नहीं हैं। आप ILDASM के साथ कुछ सुंदर अजीब सामान कर सकते हैं।

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

+1

_ "क्या मैं पूछ सकता हूं कि आप यह सामान क्यों जानना चाहते हैं?" _ 1. क्योंकि यह मजेदार और निर्देशक है! :) 2. मैं [पोस्टशर्प] (http://www.sharpcrafters.com/) का उपयोग करके एक पहलू लिख रहा था, जिसे एक निश्चित बिंदु पर बैकिंग फील्ड प्रतिनिधि के बारे में जानना था। मुझे लगा कि एक समस्या हो सकती है और एक और दृष्टिकोण का उपयोग करने में सक्षम था। –

+0

3. जैसा कि मैंने उदाहरण के साथ उठाई गई कोई समस्या नहीं देखी [यह उत्तर] (http://stackoverflow.com/questions/3783267/how-to-get-a-delegate-object-from-an-eventinfo/3783491#3783491) मुझे लगा कि यह विशेष रूप से यह पूछने योग्य सार्थक हो सकता है। मैं अपने सवालों और जादू तीनों के बीच एक सहसंबंध देखना शुरू कर रहा हूं जो उन्हें जवाब देता है। आपका बहुत बहुत धन्यवाद! :) मुझे यह भी पता है कि मुझे वास्तव में उस सी # spec के माध्यम से पढ़ना शुरू करना चाहिए। दिलचस्प सामान! –

+0

और 100% पूर्ण प्रकटीकरण, मैं एक पहलू लिख रहा हूं जो घटनाओं को बनाते समय _ "प्रतिनिधि {}" _ लिखने की आवश्यकता को समाप्त करता है, [इसलिए मेरा पिछला प्रश्न] (http://stackoverflow.com/q/9823457/590,790)। :) मैं बस इस तरह के सामान से बाहर निकलना मिलता है। भले ही यह _might_ अधिक हो जाए, यह सीखने का एक शानदार तरीका है। :) –

6

नहीं - सी # 4 कल्पना (खंड 10.8.1) से:

दसवीं कक्षा के भीतर, Ev के लिए संदर्भ छिपी हुई फ़ील्ड _ Ev को संदर्भित करने के बजाय संकलित कर रहे हैं। नाम " _Ev" मनमाना है; छिपे हुए क्षेत्र में कोई नाम या कोई नाम नहीं हो सकता है।

इसलिए स्रोत-कोड संगतता की गारंटी है, लेकिन जेनरेट किए गए फ़ील्ड के नाम के बारे में कोई गारंटी नहीं है। (प्रैक्टिस में, मैं एमएस कंपाइलर में जल्द ही इसे बदलने की उम्मीद नहीं करता - लेकिन इसकी गारंटी नहीं है, इसलिए आपको धारणा नहीं करनी चाहिए।)

+0

ठीक है, धन्यवाद! इसलिए बैकिंग प्रतिनिधि को खोजने के लिए 'गेटफिल्ड (इवेंटनाम)' का उपयोग केवल 'सही' कंपाइलर के साथ संकलित असेंबली के लिए काम करेगा। यह जानना दिलचस्प हो सकता है कि कितने कंपाइलर्स एक अलग नाम का उपयोग करते हैं। –

+1

@ स्टेवेनज्यूरिस: बस इतना नहीं - यह मानता है कि घटना को पहले स्थान पर एक क्षेत्र जैसी घटना के साथ कार्यान्वित किया जा रहा है। जैसा कि मार्क कहते हैं, अगर आपको कार्यान्वयन की पीठ के पीछे जाने की जरूरत है, तो आप इसे गलत कर रहे हैं :( –

5

किसी ईवेंट का कार्यान्वयन एक कंपाइलर कार्यान्वयन विवरण है, और कंपाइलर्स के बीच अलग है (एमएस सी # 4 में एमएस सी # < 4 के लिए एक अलग कार्यान्वयन है, और यहां तक ​​कि एमएस और ईसीएमए विनिर्देश असहमत हैं)।

व्यक्तिगत रूप से, मैं कहूंगा: यदि आपको प्रतिबिंब के माध्यम से बैकिंग फ़ील्ड तक पहुंचने की आवश्यकता है, तो आप शायद ईवेंट का सही उपयोग नहीं कर रहे हैं।

+0

_ "आप शायद घटनाओं का सही ढंग से उपयोग नहीं कर रहे हैं" _ ... पहलुओं की दुनिया एक अद्भुत जगह है। :) लेकिन आप सही हैं, बैकिंग फील्ड प्राप्त करने की आवश्यकता को समाप्त करने के लिए, मैंने पहले से ही अपने पहलू को अलग-अलग लिखने का प्रबंधन किया है। मैं सोच रहा था कि मुझे अपनी लाइब्रेरी में 'GetFieldInfo()' रखना चाहिए या नहीं, क्योंकि यह खतरनाक लग रहा था। यह अभी चला गया है ; पी –