2011-06-01 18 views
28

आज मैंने लिखा एक दिलचस्प बग पर ठोकर खाई। मेरे पास गुणों का एक सेट है जिसे एक सामान्य सेटर के माध्यम से सेट किया जा सकता है। ये गुण मूल्य प्रकार या संदर्भ प्रकार हो सकते हैं।बॉक्स किए गए मान प्रकारों की तुलना

public void SetValue(TEnum property, object value) 
{ 
    if (_properties[ property ] != value) 
    { 
     // Only come here when the new value is different. 
    } 
} 

इस विधि के लिए यूनिट परीक्षण लिखते समय मुझे पता चला कि स्थिति हमेशा मूल्य प्रकारों के लिए सच है। यह पता लगाने में मुझे लंबा समय नहीं लगा कि यह boxing/unboxing के कारण है। यह मुझे लंबे समय तक या तो नहीं लिया निम्न के कोड को समायोजित करने:

public void SetValue(TEnum property, object value) 
{ 
    if (!_properties[ property ].Equals(value)) 
    { 
     // Only come here when the new value is different. 
    } 
} 

बात मैं पूरी तरह से इस समाधान से संतुष्ट नहीं कर रहा हूँ है। जब तक मूल्य बॉक्स नहीं किया जाता है, तब तक मैं एक साधारण संदर्भ तुलना रखना चाहता हूं।

वर्तमान समाधान जो मैं सोच रहा हूं वह केवल बॉक्स किए गए मानों के लिए Equals() पर कॉल कर रहा है। a check for a boxed values करना थोड़ा अधिक लगता है। क्या कोई आसान तरीका नहीं है?

+0

आप अलग चाहते हैं निश्चित रूप से अगर बॉक्स किए गए मानों के लिए व्यवहार तो आपको यह जांचने की आवश्यकता होगी कि क्या आप बॉक्स किए गए मान से निपट रहे हैं या नहीं? – LukeH

+0

टाइप विधि के साथ इस विधि का एक सामान्य अधिभार बनाएं जहां टी: संरचना –

+1

@ लुकास, तब तक काम नहीं करेगा जब तक कि केवल 'टी' और बाधा से अधिक अंतर न हो। –

उत्तर

15

आप अलग व्यवहार की जरूरत है जब आप तो आप स्पष्ट रूप से परीक्षण के कुछ प्रकार के प्रदर्शन करने के लिए की जरूरत के लिए जा रहे एक मूल्य के प्रकार के साथ काम कर रहे हैं। मूल्य-प्रकार के लिए आपको एक स्पष्ट जांच की आवश्यकता नहीं है, क्योंकि object के रूप में टाइप किए जा रहे पैरामीटर के कारण सभी मान-प्रकार बॉक्स किए जाएंगे।

इस कोड को अपने निर्धारित मानदंडों को पूरा करना चाहिए: अगर value एक (बॉक्स्ड) मूल्य-प्रकार तो बहुरूपी Equals विधि कॉल, अन्यथा == का उपयोग संदर्भ समानता के लिए परीक्षण करने के लिए है।

public void SetValue(TEnum property, object value) 
{ 
    bool equal = ((value != null) && value.GetType().IsValueType) 
        ? value.Equals(_properties[property]) 
        : (value == _properties[property]); 

    if (!equal) 
    { 
     // Only come here when the new value is different. 
    } 
} 

(** और, हाँ, मुझे पता है कि Nullable<T> मुक्केबाजी और unboxing से संबंधित अपने स्वयं के विशेष नियमों के साथ एक मूल्य की तरह है, लेकिन यह यहाँ काफी अप्रासंगिक है।)

+0

धन्यवाद, यह पूरी तरह से काम करता प्रतीत होता है और इसमें कोई बड़ा ओवरहेड नहीं है। मुझे औसत रनटाइम में कोई वृद्धि नहीं दिखती है। –

+0

ओवरहेड बॉक्सिंग में भी है, जिसे GetType() की लागत भी है। फ्लाई पर गेटटर और सेटर प्रतिनिधि को उत्पन्न करके इसे टालने के लिए सबसे अच्छा। चीज़ों को वास्तविक प्रकार के लिए कभी भी मुक्केबाजी में रखें। –

1

चूंकि इनपुट पैरामीटर का प्रकार object है, तो आपको हमेशा विधि के संदर्भ में एक बॉक्सिंग मान प्राप्त होगा।

मुझे लगता है कि आपका एकमात्र मौका विधि के हस्ताक्षर को बदलने और विभिन्न ओवरलोड लिखना है।

+0

धन्यवाद, कल वह एक शॉट देगा। –

1

कैसे इस बारे में:

if(object.ReferenceEquals(first, second)) { return; } 
if(first.Equals(second)) { return; } 

// they must differ, right? 

अद्यतन

मुझे एहसास हुआ कि इस के रूप में एक निश्चित मामले के लिए उम्मीद से काम नहीं करता:

  • मूल्य प्रकारों के लिए, ReferenceEquals रिटर्न झूठी तो हम Equals पर वापस आते हैं, जो अपेक्षा के अनुसार व्यवहार करता है।
  • संदर्भ प्रकारों के लिए जहां ReferenceEquals सत्य लौटाता है, हम उन्हें "समान" मानते हैं।
  • संदर्भ प्रकारों के लिए जहां ReferenceEquals झूठी वापसी करता है और Equals झूठा रिटर्न देता है, हम उन्हें अपेक्षा के अनुसार "अलग" मानते हैं।
  • संदर्भ प्रकार जहां ReferenceEquals रिटर्न झूठी और Equals रिटर्न सच है, हम इस पर विचार के लिए उन्हें "एक ही" भले ही हम चाहते हैं "अलग"

तो सबक "चालाक नहीं मिलता है"

+0

यदि मान को केवल बॉक्स किया गया था, वैल्यू प्रकारों के मामले में, पहला 'if' हमेशा झूठा उपज करेगा, इस प्रकार यह ओपी समस्या का समाधान नहीं करेगा। – Simone

+1

समस्या, जैसा कि मैं इसे समझता हूं, "मैं एक साधारण संदर्भ तुलना रखना चाहता हूं, जब तक कि मूल्य बॉक्स न हो।" यह ऐसा करेगा। लेकिन जैसा कि शॉन का जवाब कहता है, "अगर किसी ने कक्षा में अधिग्रहण किया है() (क्योंकि) इस वर्ग के लिए समानता अर्थशास्त्र को बदलना चाहते हैं, और ऐसा करना बेहतर है यदि आपके पास कोई अनिवार्य कारण नहीं है" । मैंने माना कि पूछताछ का एक अनिवार्य कारण है। –

+0

यह एक सही धारणा है। ; पी –

10

बराबर है() आमतौर पर पसंदीदा दृष्टिकोण है।

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

+0

समस्या यह है कि 'बराबर' ओवरराइड हो सकता है। हालांकि दो वस्तुएं बराबर हैं, इसका मतलब यह नहीं है कि एक नई वस्तु (एक अलग संदर्भ के साथ) सेट नहीं है। –

0

मुझे लगता है

मैं एक साधारण संदर्भ तुलना रखने के लिए, जब तक कि मूल्य बॉक्सिंग है चाहते हैं।

कुछ हद तक

के बराबर है मूल्य बॉक्सिंग रहा है, तो मैं एक गैर- "सरल संदर्भ तुलना" कर देंगे।

इसका मतलब है कि आपको सबसे पहले जो करना होगा, यह जांचना है कि मूल्य बॉक्स किया गया है या नहीं।

यदि कोई ऑब्जेक्ट एक बॉक्सिंग मान प्रकार है या नहीं, यह जांचने के लिए कोई तरीका मौजूद है, तो यह कम से कम जटिल हो सकता है कि आपने उस "ओवरकिल" विधि के रूप में जटिल होना चाहिए जब तक कि यह सबसे आसान तरीका न हो। फिर भी, यह निर्धारित करने के लिए एक "सरल तरीका" होना चाहिए कि कोई ऑब्जेक्ट एक बॉक्स किए गए मान प्रकार है या नहीं। यह असंभव है कि यह "सरल तरीका" ऑब्जेक्ट बराबर() विधि का उपयोग करने से सरल है, लेकिन मैंने इस प्रश्न को केवल मामले में खोजने के लिए बुकमार्क किया है।

(यकीन नहीं अगर मैं तार्किक था)

संबंधित मुद्दे