2010-08-17 14 views
32

कोड अशक्त कोड == ऑपरेटर या regular Object.Equals का उपयोग करता है की तुलना में अधिक मजबूत की जांच करने के static Object.Equals का उपयोग करता है है? क्या बाद वाले दो अतिसंवेदनशील होने के लिए कमजोर नहीं हैं कि शून्य के लिए जांच की अपेक्षा की जाती है (उदाहरण के लिए तुलनात्मक मूल्य शून्य है)?बराबर (आइटम, नल) या आइटम == बातिल

if (Equals(item, null)) { /* Do Something */ } 

अधिक इस से मजबूत:

if (item == null) { /* Do Something */ } 

मैं व्यक्तिगत रूप से बाद के वाक्य रचना को पढ़ने के लिए आसान लगता है

दूसरे शब्दों में, यह है। कोड लिखते समय इसे टालना चाहिए जो लेखक के नियंत्रण (जैसे पुस्तकालय) के बाहर वस्तुओं को संभाल लेगा? क्या इसे हमेशा से बचा जाना चाहिए (जब शून्य की जांच हो)? क्या यह सिर्फ बाल-विभाजन है?

उत्तर

43

इस प्रश्न के लिए कोई आसान जवाब नहीं है। कोई भी जो हमेशा एक या दूसरे का उपयोग करता है, मेरी राय में आपको खराब सलाह दे रहा है।

वास्तव में कई अलग-अलग विधियां हैं जिन्हें आप ऑब्जेक्ट इंस्टेंस की तुलना करने के लिए कॉल कर सकते हैं। दो वस्तु उदाहरणों a और b देखते हुए, आप लिख सकते हैं:

  • Object.Equals(a,b)
  • Object.ReferenceEquals(a,b)
  • a.Equals(b)
  • a == b

ये सब अलग अलग बातें कर सकता है!

Object.Equals(a,b) जाएगा (डिफ़ॉल्ट रूप से) संदर्भ प्रकार और मूल्य प्रकार पर बिटवाइज़ तुलना पर संदर्भ समानता तुलना करते हैं।MSDN प्रलेखीकरण से:

बराबर के डिफ़ॉल्ट कार्यान्वयन संदर्भ प्रकार के लिए संदर्भ समानता, और मूल्य प्रकार के लिए बिटवाइज़ समानता का समर्थन करता है। संदर्भ समानता का अर्थ ऑब्जेक्ट संदर्भ है जो की तुलना में उसी ऑब्जेक्ट को संदर्भित करता है। बिटवाईव समानता का अर्थ है की तुलना में तुलना की जाती है, उसी बाइनरी प्रतिनिधित्व है।

ध्यान दें कि व्युत्पन्न प्रकार बराबर विधि को लागू मूल्य समानता पर ओवरराइड कर सकता है। मान समानता का अर्थ है तुलना की गई वस्तुओं समान मूल्य है लेकिन अलग बाइनरी प्रस्तुतिकरण हैं।

ऊपर दिए गए अंतिम अनुच्छेद पर ध्यान दें ... हम बाद में इस पर चर्चा करेंगे।

Object.ReferenceEquals(a,b) केवल संदर्भ समानता तुलना करता है। यदि पास किए गए प्रकार बॉक्स किए गए मान प्रकार हैं, तो परिणाम हमेशा false होता है।

a.Equals(b)Object की आभासी उदाहरण विधि है, जो a के प्रकार कुछ भी यह चाहता है ऐसा करने के लिए रद्द कर सकते थे कहता है। कॉल वर्चुअल प्रेषण का उपयोग करके किया जाता है, इसलिए चलने वाला कोड रनटाइम प्रकार a पर निर्भर करता है।

a == ba की ** संकलन समय प्रकार * के स्थिर अतिभारित ऑपरेटर invokes। यदि उस ऑपरेटर का कार्यान्वयन a या b पर उदाहरण विधियों को आमंत्रित करता है, तो यह पैरामीटर के रनटाइम प्रकारों पर भी निर्भर हो सकता है। के बाद से प्रेषण अभिव्यक्ति में प्रकार के आधार पर किया जाता है, निम्नलिखित विभिन्न परिणाम हो सकता है:

Frog aFrog = new Frog(); 
Frog bFrog = new Frog(); 
Animal aAnimal = aFrog; 
Animal bAnimal = bFrog; 
// not necessarily equal... 
bool areEqualFrogs = aFrog == bFrog; 
bool areEqualAnimals = aAnimal = bAnimal; 

तो, हाँ, वहाँ operator == का उपयोग कर nulls के लिए जांच करने के लिए जोखिम है। प्रैक्टिस में, अधिकांश प्रकार ओवरलोड == - लेकिन कभी गारंटी नहीं है।

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

लेकिन Object.Equals() के स्थिर संस्करण के बारे में आप क्या पूछते हैं? क्या यह चल रहा उपयोगकर्ता कोड समाप्त हो सकता है? खैर, यह पता चला है कि जवाब हाँ है।

((object)a == (object)b) || (a != null && b != null && a.Equals(b)) 

आप खुद के लिए यह कोशिश कर सकते हैं: Object.Equals(a,b) के कार्यान्वयन की तर्ज पर कुछ के लिए विस्तारित उपयोगकर्ता कोड जब न चलाने के लिए Object.Equals(a,b):

class Foo { 
    public override bool Equals(object obj) { return true; } } 

var a = new Foo(); 
var b = new Foo(); 
Console.WriteLine(Object.Equals(a,b)); // outputs "True!" 

एक परिणाम के रूप में, यह बयान के लिए संभव है कॉल के प्रकार null हैं।ध्यान दें कि Object.Equals(a,b)Equals() के इंस्टेंस संस्करण को कॉल करता है जब तर्क में से कोई भी शून्य नहीं होता है।

संक्षेप में, आप किस प्रकार की तुलनात्मक व्यवहार प्राप्त करते हैं, इस पर निर्भर करता है कि आप किस विधि को कॉल करना चुनते हैं। हालांकि, यहां एक टिप्पणी: माइक्रोसॉफ्ट आधिकारिक तौर पर Object.Equals(a,b) के आंतरिक व्यवहार को दस्तावेज नहीं करता है। आप एक लोहे के किसी अन्य कोड चल रहा है बिना अशक्त के लिए एक संदर्भ की तुलना में पहने गारंटी के की जरूरत है, तो आप Object.ReferenceEquals() हैं:

Object.ReferenceEquals(item, null); 

इस विधि आशय extremently स्पष्ट करता है - आप विशेष रूप से तुलना होने का परिणाम उम्मीद कर रहे हैं संदर्भ समानता के लिए दो संदर्भों में से। a.Equals(null) या a == null

जो संभवतः:

"अरे, यह अजीब है, चलो इसके साथ की जगह है: यहाँ Object.Equals(a,null) की तरह कुछ का उपयोग करने पर लाभ यह है कि यह कम संभावना है कि किसी को बाद में आकर कहेंगे है । अलग हो सकता है।

चलो कुछ व्यावहारिकता यहाँ इंजेक्षन हालांकि, करते हैं। अब तक हम तुलना के विभिन्न साधनों अलग परिणाम उपज के लिए क्षमता के बारे में बात की है हालांकि यह निश्चित रूप से मामला है, वहाँ कुछ प्रकार के होते हैं, जहां यह है wr के लिए सुरक्षित यह a == null। अंतर्निहित .NET वर्ग जैसे String और Nullable<T> तुलना के लिए अच्छी तरह से परिभाषित अर्थशास्त्र है। इसके अलावा, वे sealed हैं - विरासत के माध्यम से उनके व्यवहार में किसी भी बदलाव को रोकना। निम्नलिखित बहुत आम (और सही) है:

string s = ... 
if(s == null) { ... } 

यह अनावश्यक (और बदसूरत) है लिखने के लिए:

if(ReferenceEquals(s,null)) { ... } 
तो कुछ सीमित मामलों में

, का उपयोग कर == सुरक्षित, और उचित है।

+0

मैंने सोचा कि मेरा जवाब (प्रॉक्सी द्वारा माइक्रोसॉफ्ट का जवाब) एक बहुत ही सरल जवाब है। – mquander

+4

जैसे प्रश्न: * "क्या मुझे हमेशा एक्स/कभी नहीं करना चाहिए" * प्रश्न में विषय की बारीकियों के बारे में ज्ञान अंतर को इंगित करता है। मुझे लगा कि थोड़ा और विस्तार यहां स्पष्टीकरण के लिए उपयोगी होगा कि मुझे क्यों नहीं लगता कि एक साधारण उत्तर सार्थक है। – LBushkin

+0

स्थैतिक 'ऑब्जेक्ट। एक्वाल्स (ए, बी)' विधि, वास्तव में, ऑब्जेक्ट 'ए' पर अधिभारित/वर्चुअल 'बराबर' विधि को कॉल कर सकती है। अगर मैं सही ढंग से याद करता हूं, तो यह कुछ ('ऑब्जेक्ट) ए == (ऑब्जेक्ट) बी) करता है। || (ए! = नल && बी! = नल और ए। एक्वाल्स (बी)) '। (यह 'शून्य' की तुलना करते समय अप्रासंगिक है, जो ओपी पूछता है, लेकिन सामान्य मामले के लिए प्रासंगिक है।) – LukeH

4

if (Equals(item, null)) कोई और अधिक if (item == null) से मजबूत है, और मैं इसे बूट करने के लिए अधिक संशय है।

+0

किसी के लिए 'बराबर' ओवरराइड किए बिना '==' ऑपरेटर को अधिभारित करना संभव है। यह एक खराब डिजाइन होगा, लेकिन दोनों के बीच समानता तुलना के अर्थशास्त्र के लिए यह पूरी तरह से संभव है।साथ ही, यदि '==' ऑपरेटर ओवरलोड हो गया है, तो यह अंतर्निहित 'ऑब्जेक्ट्स। एक्वाल्स()' विधि से पूरी तरह से कुछ अंतर कर सकता है - जो मुझे लगता है कि संदर्भ संदर्भ समानता के लिए जांच करता है। – LBushkin

2

framework guidelines सुझाव है कि आप मूल्य के रूप में समानता Equals का इलाज, (दो वस्तुओं एक ही जानकारी, यानी की तुलना गुण प्रतिनिधित्व करते हैं कि क्या देखने के लिए जाँच), और == संदर्भ समानता के रूप में, अपरिवर्तनीय वस्तुओं के अपवाद के साथ, जिसके लिए आप शायद ओवरराइड करना चाहिए == मूल्य समानता होने के लिए।

तो, दिशानिर्देशों को यहां लागू करने पर विचार करें, जो भी अर्थपूर्ण रूप से समझदार है चुनें। यदि आप अपरिवर्तनीय वस्तुओं से निपट रहे हैं, और आप उम्मीद करते हैं कि दोनों विधियां समान परिणाम उत्पन्न करेंगी, तो मैं स्पष्टता के लिए == का उपयोग करूंगा।

+2

माइक्रोसॉफ्ट दिशानिर्देश नल के मुद्दे को संबोधित नहीं करते हैं, यही सवाल है। सबसे महत्वपूर्ण बात यह है कि, "myString == null" एक सुरक्षित परीक्षण है, "myString.Equals (null)" मेरा स्ट्रिंग शून्य होने पर अपवाद का कारण बन जाएगा। इसके अलावा, माइक्रोसॉफ्ट दिशानिर्देशों में ऑब्जेक्ट। एक्वाल्स (myObject, b) और myObject.Equals (बी) के बीच अंतर का भी उल्लेख नहीं है। पूर्व मजबूत है; उत्तरार्द्ध एक अपवाद देता है अगर myObject शून्य है। इसलिए, जब आप जो लिंक प्रदान करते हैं वह उपयोगी होता है, तो यह पोस्टर के प्रश्न का उत्तर नहीं है। – ToolmakerSteve

1

"... कोड लिखना जो लेखक के नियंत्रण के बाहर वस्तुओं को संभाल लेगा ...", मैं इंगित करता हूं कि स्थिर Object.Equals और == ऑपरेटर स्थिर तरीके हैं और इसलिए वर्चुअल/ओवरराइड नहीं हो सकते हैं। स्थिर कार्यान्वयन के आधार पर संकलन समय पर कौन सा कार्यान्वयन कहा जाता है निर्धारित किया जाता है। दूसरे शब्दों में, बाहरी पुस्तकालय के लिए आपके संकलित कोड में दिनचर्या का एक अलग संस्करण प्रदान करने का कोई तरीका नहीं है।

+0

** यह कथन पूरी तरह से सही नहीं है। ** ऑपरेटर '==' के कार्यान्वयन के लिए एक उदाहरण पर वर्चुअल विधि को कॉल करने के लिए संभव है। इसका अर्थ यह है कि वास्तव में यह संभव है * चीजों के होने के लिए जो अभिव्यक्ति के प्रकारों पर आधारित नहीं हैं, बल्कि रनटाइम प्रकारों पर शामिल हैं। – LBushkin

+0

और यह स्थिर 'ऑब्जेक्ट पर लागू होता है। एक्वाल्स (ए, बी)' विधि भी, जो कुछ ((ऑब्जेक्ट) ए == (ऑब्जेक्ट) बी) करता है || (ए! = null && b! = null && a.Equals (बी)) 'यानी, यह ऑब्जेक्ट' ए 'पर आभासी' बराबर 'विधि को कॉल कर सकता है। – LukeH

+0

@LBushkin आपका बिंदु मान्य है, हालांकि यह मेरे कथन को 'पूरी तरह से सही नहीं' होने के बराबर नहीं है (पंड क्षमा करें)। –

1

आप (स्मृति में एक ही स्थान) पहचान का परीक्षण करना चाहते हों:

ReferenceEquals(a, b)

nulls संभालती है। और अतिसंवेदनशील नहीं है। 100% सुरक्षित

लेकिन सुनिश्चित करें कि आप वास्तव में पहचान परीक्षण चाहते हैं। निम्नलिखित पर विचार करें:

ReferenceEquals(new String("abc"), new String("abc"))

जो false देता है।इसके विपरीत:

Object.Equals(new String("abc"), new String("abc"))

और

(new String("abc")) == (new String("abc"))

दोनों true लौट आते हैं।

यदि आप इस स्थिति में true का उत्तर देने की उम्मीद कर रहे हैं, तो आप एक समानता परीक्षण चाहते हैं, पहचान पहचान नहीं। अगला भाग देखें।


आप समानता (समान सामग्री) का परीक्षण करना चाहते हों:

  • उपयोग "a == b" यदि संकलक शिकायत नहीं है।

  • यदि इसे अस्वीकार कर दिया गया है (यदि चर का प्रकार "==" ऑपरेटर परिभाषित नहीं करता है), तो "Object.Equals(a, b)" का उपयोग करें।

  • यदि आप तर्क जहां एक करने के लिए जाना जाता है अशक्त नहीं हो के अंदर कर रहे हैं, तो आप अधिक पठनीय "a.Equals(b)" का उपयोग कर सकते हैं। उदाहरण के लिए, "यह। एक्वाल्स (बी)" सुरक्षित है। या यदि "ए" एक ऐसा क्षेत्र है जो निर्माण समय पर शुरू होता है, और उस क्षेत्र में उपयोग किए जाने वाले मूल्य के रूप में नल को पारित किया जाता है तो कन्स्ट्रक्टर अपवाद फेंकता है।

अब, मूल प्रश्न को संबोधित करने के:

प्रश्न: क्या ये कोड है कि रिक्त सही ढंग से संभाल नहीं करता है, एक अपवाद है, जिसके परिणामस्वरूप के साथ कुछ वर्ग में अधिरोहित जा रहा है, के लिए अतिसंवेदनशील?

ए: हां। 100% सुरक्षित इक्विटी परीक्षण प्राप्त करने का एकमात्र तरीका स्वयं को नल के लिए प्री-टेस्ट करना होगा।

लेकिन क्या आपको चाहिए? बग उसमें होगा (hypothetical भविष्य खराब वर्ग), और यह एक सीधा प्रकार की विफलता होगी। डीबग करने और ठीक करने के लिए आसान (जो भी कक्षा की आपूर्ति करता है)। मुझे संदेह है कि यह एक समस्या है जो अक्सर होती है, या ऐसा होने पर लंबे समय तक बनी रहती है।

अधिक विस्तृत ए: Object.Equals(a, b) खराब लिखित कक्षा के चेहरे पर काम करने की संभावना है। यदि "ए" शून्य है, ऑब्जेक्ट क्लास इसे स्वयं संभाल लेगा, इसलिए वहां कोई जोखिम नहीं है। यदि "बी" शून्य है, तो "ए" का डायनामिक (रन-टाइम संकलन-समय) प्रकार निर्धारित करता है कि "बराबर" विधि क्या कहती है। बुलाया जाने वाला तरीका केवल "बी" शून्य होने पर सही तरीके से काम करना है। जब तक बुलाया गया तरीका बेहद खराब लिखा नहीं जाता है, तब तक पहला कदम यह निर्धारित करता है कि "बी" एक प्रकार है जो यह समझता है।

तो Object.Equals(a, b) पठनीयता/कोडिंग_फोर्ट और सुरक्षा के बीच एक उचित समझौता है।

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