क्यों C # एक दूसरे के साथ दो ऑब्जेक्ट प्रकारों की तुलना करने में विफल रहता है, लेकिन VB नहीं करता है?


152

मेरे पास C # में दो ऑब्जेक्ट हैं और यह नहीं जानते कि क्या यह बूलियन या कोई अन्य प्रकार है। हालाँकि जब मैं उन C की तुलना करने की कोशिश करता हूं तो # सही उत्तर देने में विफल रहता है। मैं VB.NET के साथ एक ही कोड की कोशिश की है और यह किया है!

अगर कोई समाधान है तो क्या कोई मुझे बता सकता है कि इसे कैसे ठीक किया जाए?

सी#:

object a = true;
object b = true;
object c = false;
if (a == b) c = true;
MessageBox.Show(c.ToString()); //Outputs False !!

VB.NET:

Dim a As Object = True
Dim b As Object = True
Dim c As Object = False
If (a = b) Then c = True
MessageBox.Show(c.ToString()) '// Outputs True

3
क्या होगा यदि आप समानता तुलनित्र को बदलते हैं a.Equals(b)?
जेसन मेक्ले

8
यह शैक्षणिक उद्देश्यों के लिए एक अच्छा सवाल है।
लोबो

10
क्योंकि आपका VB.NET कोड आपके C # कोड के बराबर नहीं है।
सिक्योरिटी हाउंड

9
जब आप असाइन करते हैं aतो आपको बॉक्सिंग मिलती है और एक बॉक्स होता है true। जब आप असाइन करते हैं bतो आपको एक और बॉक्स भी मिलता है true। जब आप तुलना करते हैं aऔर b, क्योंकि दोनों संकलन-समय प्रकार के हैं object, तो आप operator ==(object, object)C # भाषा विनिर्देश द्वारा परिभाषित अधिभार कहते हैं । यह ओवरलोड चेक करता है कि संदर्भ एक ही वस्तु पर जाते हैं या नहीं। चूंकि आपके पास दो बक्से हैं, इसलिए परिणाम है false, और "आपके" के तहत "बयान" ifनहीं चलेगा। इसे बेहतर समझने के लिए, इस के असाइनमेंट को बदलने का प्रयास bकरें: object b = a;अब आपके पास सिर्फ एक बॉक्स है।
जेपी स्टिग नीलसन

3
मेरे पास कहने से पहले "सावधान रहना चाहिए कि VB.NET और C # एक ही भाषा को एक अलग उच्चारण के साथ बोला जाता है - वे नहीं हैं"
AakashM

जवाबों:


168

C # में, ==ऑपरेटर (जब संदर्भ प्रकार के भावों पर लागू होता है) एक संदर्भ समानता की जांच करता है जब तक कि यह अतिभारित न हो । आप दो संदर्भों की तुलना कर रहे हैं जो मुक्केबाजी रूपांतरणों का परिणाम हैं, इसलिए वे अलग संदर्भ हैं।

EDIT: प्रकारों के साथ ==, जो अधिभारित करते हैं , आप विभिन्न व्यवहार प्राप्त कर सकते हैं - लेकिन यह संकलन- प्रकार के भावों पर आधारित है । उदाहरण के लिए, stringप्रदान करता है ==(string, string):

string x = new string("foo".ToCharArray());
string y = new string("foo".ToCharArray());
Console.WriteLine(x == y); // True
Console.WriteLine((object) x == (object) y); // False

यहां पहली तुलना ओवरलोड ऑपरेटर का उपयोग कर रही है, लेकिन दूसरी "डिफ़ॉल्ट" संदर्भ तुलना का उपयोग कर रही है।

VB में, =ऑपरेटर एक पूरे बहुत अधिक काम करता है - यह सिर्फ उपयोग करने के बराबर नहीं है object.Equals(x, y), क्योंकि चीजें इस बात Option Compareको प्रभावित कर सकती हैं कि पाठ की तुलना कैसे की जाती है।

मौलिक रूप से ऑपरेटर उसी तरह से काम नहीं करते हैं और उसी तरह काम करने का इरादा नहीं रखते हैं ।


17
+1 मैं जानता था कि आप आस-पास रहेंगे, आप इस प्रकार के रहस्यमय सवालों से प्यार करते हैं :)
अब्दुस्सलाम बेन हज

3
@AbZy: मुझे उम्मीद है कि =वीबी में जो किया गया था, उसके बारे में अधिक विस्तृत विवरण देने में सक्षम होने के लिए , लेकिन कल्पना बहुत स्पष्ट नहीं है।
जॉन स्कीट

दिलचस्प बात है, लेकिन गतिशील वस्तु को बदलते हुए VB
VladL

4
@ व्लाद: हाँ, क्योंकि तब यह निष्पादन-समय के प्रकारों से जाना जाएगा, और bool == boolतुलना प्रदर्शन करेगा ।
जॉन स्कीट

1
@ मेहदी लोबो ने कोड प्रदान किया हो सकता है, लेकिन जॉन के विपरीत, उसका उत्तर भी गलत है।
सर्व

79

जॉन के जवाब के अलावा जो सी # चीजों के बारे में बताता है, यहां बताया गया है कि वीबी क्या करता है:

VB के साथ Option Strict On, मूल्य समानता के लिए = हमेशा परीक्षण और संदर्भ समानता के लिए कभी नहीं की तुलना । वास्तव में, आपका कोड एक बार स्विच करने के बाद भी संकलित नहीं करता है Option Strict Onक्योंकि System.Objectकोई परिभाषित नहीं करता हैOperator= । आपके पास हमेशा यह विकल्प होना चाहिए , यह एक वीनस फ्लाईट्रैप की तुलना में कीड़े को अधिक प्रभावी ढंग से पकड़ता है (हालांकि आपके विशेष मामले में यह शिथिल व्यवहार वास्तव में सही काम करता है)। 1

वास्तव में, के साथ Option Strict On, वीबी से सी # भी सख्त बर्ताव करता है: में सी #, a == b या तो कॉल को ट्रिगर करता है SomeType.operator==(a, b)या, यदि यह मौजूद नहीं है, तो संदर्भ समानता तुलना (जो कॉल करने के बराबर है object.ReferenceEquals(a, b)) को आमंत्रित करता है ।

दूसरी ओर VB में, तुलना a = b हमेशा समानता ऑपरेटर को आमंत्रित करती है। 2 यदि आप संदर्भ समानता तुलना का उपयोग करना चाहते हैं, तो आपको उपयोग करना होगाa Is b (जो कि, एक बार फिर से, उसी तरह Object.ReferenceEquals(a, b))।


1) यहाँ एक अच्छा संकेत है कि क्यों उपयोग Option Strict Offकरना एक बुरा विचार है: मैंने कुछ वर्षों पहले तक .NET की आधिकारिक रिलीज़ से पहले, लगभग एक दशक तक VB.NET का उपयोग किया है, और मुझे पूरी तरह से पता नहीं है कि a = bइसके साथ क्या होता है Option Strict Off। यह किसी प्रकार की समानता की तुलना करता है, लेकिन वास्तव में क्या होता है और क्यों, कोई विचार नहीं है। यह C # की dynamicसुविधा से अधिक जटिल है , हालांकि (क्योंकि यह एक अच्छी तरह से प्रलेखित एपीआई पर निर्भर है)। यहाँ MSDN क्या कहता है:

क्योंकि मजबूत टाइपिंगOption Strict On प्रदान करता है , डेटा हानि के साथ अनपेक्षित प्रकार के रूपांतरणों को रोकता है, देर से बाध्यकारी को रोकता है, और प्रदर्शन में सुधार करता है, इसके उपयोग की जोरदार सिफारिश की जाती है।

2) जॉन ने एक अपवाद का उल्लेख किया है, तार, जहां समानता तुलना पिछड़े संगतता के कारणों के लिए कुछ और चीजें करती हैं।


4
+1। मुझे लगता है कि यह एक ऐसा मामला है, जहां VB.NET के डिज़ाइनर VB6 और VBA से आने वाले प्रोग्रामरों के लिए भाषा को "बस काम" करने में सफल रहे, जहाँ OOP बहुत कम प्रमुख है और इसलिए संदर्भ समानता की अवधारणा बहुत कम महत्वपूर्ण है। एक VB कोडर वस्तुओं और उसके आगे के बारे में ज्यादा सोचे बिना अच्छा वर्किंग कोड लिख सकता है।
जॉन एम गैंट

5
+1 यह उतनी नहीं है जितना वास्तव में होना चाहिए। उपयोग न करने Option Strict Onको एक आपराधिक अपराध माना जाता है ...
हिरण हंटर

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

4

ऑपरेटर "==" के साथ ऑब्जेक्ट इंस्टेंस की तुलना नहीं की जाती है। आपको विधि "बराबर" का उपयोग करना चाहिए। "==" ऑपरेटर संदर्भों की तुलना कर रहा है, वस्तुओं की नहीं।

इसे इस्तेमाल करे:

public class MyObject
{
    public MyObject(String v)
    {
        Value = v;
    }
    public String Value { get; set; }
}

MyObject a = new MyObject("a");
MyObject b = new MyObject("a");
if(a==b){
    Debug.WriteLine("a reference is equal to b reference");
}else{
    Debug.WriteLine("a reference is not equal to b reference");
}
if (a.Equals(b)) {
    Debug.WriteLine("a object is equal to b object");
} else {
    Debug.WriteLine("a object is not equal to b object");
}

परिणाम:

a reference is not equal to b reference
a object is not equal to b object

अब, यह प्रयास करें:

public class MyObject
{
    public MyObject(String v)
    {
        Value = v;
    }
    public String Value { get; set; }

    public bool Equals(MyObject o)
    {
        return (Value.CompareTo(o.Value)==0);
    }
}
MyObject a = new MyObject("a");
MyObject b = new MyObject("a");
if(a==b){
    Debug.WriteLine("a reference is equal to b reference");
}else{
    Debug.WriteLine("a reference is not equal to b reference");
}
if (a.Equals(b)) {
    Debug.WriteLine("a object is equal to b object");
} else {
    Debug.WriteLine("a object is not equal to b object");
}

परिणाम:

a reference is not equal to b reference
a object is equal to b object

1
यह केवल इसलिए है क्योंकि आपने ओवरराइड नहीं किया है operator ==। यदि आप उस ऑपरेटर को ओवररोड करते हैं और बराबर नहीं होता है तो आपका आउटपुट उलट हो जाएगा। संदर्भों की तुलना करने के लिए operator ==कुछ भी अंतर्निहित नहीं है और मूल्यों की तुलना करने के बारे में निहित कुछ भी नहीं है Equals। वे समानता का निर्धारण करने के सिर्फ दो तरीके हैं; दोनों में एक संदर्भ तुलना के डिफ़ॉल्ट कार्यान्वयन हैं, और दोनों को आप जो भी करना चाहते हैं उन्हें करने के लिए ओवरराइड किया जा सकता है। केवल अन्य अंतर यह है कि Equalsआभासी है, और operator ==नहीं है।
सर्व

1
@ सर्वे: ध्यान दें कि आप ओवरराइड नहीं ==कर सकते - आप इसे केवल ओवरलोड कर सकते हैं ।
जॉन स्कीट

1
क्षमा करें, -1। यह उत्तर केवल गलत है और इसे स्वीकार नहीं किया जाना चाहिए।
कोनराड रुडोल्फ

कहीं न कहीं एक जावा प्रश्न है जो इस उत्तर की प्रतीक्षा कर रहा है।
चाड शागिंस

3

मुद्दा यह है कि C # में == ऑपरेटर एक स्थिर विधि के लिए एक कॉल है (अच्छी तरह से, शायद तकनीकी रूप से नहीं, लेकिन यह दो मापदंडों के संकलन समय प्रकार के आधार पर ऐसा हो सकता है) । उन वस्तुओं के वास्तविक रनटाइम प्रकार क्या मायने नहीं रखते हैं।

उस संकलन समय के आधार पर कंपाइलर यह निर्धारित करेगा कि किस कार्यान्वयन का operator ==उपयोग करना है। यह डिफ़ॉल्ट का उपयोग कर सकता हैobject कार्यान्वयन का उपयोग कर सकता है, यह भाषा द्वारा प्रदान किए गए सांख्यिक अधिभार में से एक का उपयोग कर सकता है, या यह एक उपयोगकर्ता परिभाषित कार्यान्वयन हो सकता है।

यह VB से भिन्न है कि VB संकलन समय पर कार्यान्वयन का निर्धारण नहीं करता है। यह रनटाइम तक इंतजार करता है और दो मापदंडों का निरीक्षण करता है जो यह निर्धारित करने के लिए दिया जाता है कि ==ऑपरेटर को किस कार्यान्वयन का उपयोग करना चाहिए।

आपके कोड में बूलियन मान हैं, लेकिन वे उन चर में हैं जो प्रकार के हैं object। क्योंकि चर प्रकार का है object, C # संकलक के objectकार्यान्वयन का उपयोग करता है ==, जो संदर्भों की तुलना करता है , न कि वस्तु उदाहरणों की। चूंकि बूलियन मूल्य बक्से हैं, इसलिए उनका संदर्भ समान नहीं है, भले ही उनके मूल्य समान हों।

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


सी # के लिए ठीक लग रहा है; मुझे =पक्का पता नहीं है कि वीबी में वास्तव में क्या कहना है।
जॉन स्कीट

@JonSkeet मेला काफी
सर्व करें

प्रति msdn.microsoft.com/en-us/library/cey92b0t(v=vs.110).aspx , अनुभाग में "रिलेशनल तुलना ऑपरेटर्स के साथ Typeless प्रोग्रामिंग": =, जैसे अन्य सभी संबंधित तुलना ऑपरेटरों के साथ-साथ <, >=आदि , विशेष उपचार दिया जाता है जब दोनों या ऑपरेटर के दोनों ओर होता है Object। यह विशेष उपचार इसलिए किया जाता है ताकि VB6 प्रोग्रामर, जो Variantपूर्व- .NET VB के रूप में ज्ञात एक प्रकार का उपयोग करने के आदी हैं , Objectवे VB.Net का उपयोग उन तरीकों से कर सकते हैं जो वे पहले उपयोग कर चुके हैं Variant
रस्साकसी

इसे दूसरे तरीके से डालने के लिए, और ओवरलोडिंग के प्रभावों को छोड़कर Option Strict On, वीबी =को एक बॉक्स में Objectतब तक unboxing की ओर रखा जाता है, जब तक कि वह स्ट्रिंग या न्यूमेरिक को प्राप्त न कर सके।
रास्कर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.