हमें C = में = = और = दोनों को परिभाषित क्यों करना चाहिए?


346

C # कंपाइलर के लिए आवश्यक है कि जब भी कोई कस्टम प्रकार ऑपरेटर को परिभाषित करे == , तो उसे भी परिभाषित किया जाना चाहिए !=( यहाँ देखें )।

क्यों?

मैं यह जानने के लिए उत्सुक हूं कि डिजाइनरों ने इसे आवश्यक क्यों समझा और संचालक दोनों में से किसी एक के लिए उचित कार्यान्वयन के लिए संकलक डिफ़ॉल्ट क्यों नहीं कर सकता है जब केवल अन्य मौजूद हैं। उदाहरण के लिए, लुआ आपको केवल समानता ऑपरेटर को परिभाषित करने देता है और आपको दूसरे को मुफ्त में मिलता है। C # आपको या तो == या दोनों == और! = को परिभाषित करने के लिए कहकर ऐसा ही कर सकता है और फिर स्वचालित रूप से अनुपस्थित! = ऑपरेटर को संकलित कर सकता है !(left == right)

मैं समझता हूं कि अजीब कोने के मामले हैं जहां कुछ इकाइयां न तो समान और न ही असमान हो सकती हैं, (जैसे IEEE-754 NaN की), लेकिन वे अपवाद जैसे लगते हैं, नियम नहीं। इसलिए यह स्पष्ट नहीं करता है कि C # कंपाइलर डिजाइनरों ने अपवाद को नियम क्यों बनाया।

मैंने खराब कारीगरी के मामलों को देखा है जहां समानता ऑपरेटर को परिभाषित किया गया है, फिर असमानता ऑपरेटर प्रत्येक और हर तुलना के साथ एक कॉपी-पेस्ट है और हर && एक पर स्विच किया जाता है || (आपको बिंदु मिलता है ... मूल रूप से! (a = b) डी मॉर्गन के नियमों के माध्यम से विस्तार किया गया)। यह खराब अभ्यास है कि संकलक डिजाइन द्वारा समाप्त कर सकता है, जैसा कि लूआ के साथ होता है।

नोट: एक ही ऑपरेटरों के लिए रखती है <> <=> =। मैं उन मामलों की कल्पना नहीं कर सकता जहाँ आपको अप्राकृतिक तरीकों से परिभाषित करने की आवश्यकता होगी। Lua आपको केवल <और <= परिभाषित करता है और => और> स्वाभाविक रूप से फॉर्मर्स की उपेक्षा के माध्यम से परिभाषित करता है। C # समान (कम से कम 'डिफ़ॉल्ट रूप से) क्यों नहीं करता है?

संपादित करें

जाहिर तौर पर वैध कारण हैं कि वे प्रोग्रामर को समानता और असमानता के लिए चेक लागू कर सकते हैं। कुछ उत्तर उन मामलों की ओर इशारा करते हैं जहां यह अच्छा हो सकता है।

हालाँकि, मेरे प्रश्न का कर्नेल, यह क्यों C # में जबरन आवश्यक है जब आमतौर पर यह तार्किक रूप से आवश्यक नहीं होता है?

यह .NET इंटरफेस जैसे डिज़ाइन विकल्पों के विपरीत भी हड़ताली है Object.Equals, IEquatable.Equals IEqualityComparer.Equalsजहां NotEqualsसमकक्ष की कमी से पता चलता है कि रूपरेखा !Equals()वस्तुओं को असमान मानती है और वह है। इसके अलावा, जैसी कक्षाएं Dictionaryऔर विधियाँ .Contains()विशेष रूप से पूर्वोक्त इंटरफेस पर निर्भर करती हैं और परिभाषित होने पर भी सीधे ऑपरेटरों का उपयोग नहीं करती हैं। वास्तव में, जब ReSharper समानता सदस्यों को उत्पन्न करता है, तो यह दोनों को परिभाषित करता है ==और !=इसके संदर्भ में Equals()भी और तब भी जब उपयोगकर्ता सभी को ऑपरेट करने के लिए चुनता है। वस्तु समानता को समझने के लिए फ्रेमवर्क द्वारा समानता ऑपरेटरों की आवश्यकता नहीं होती है।

असल में, .NET फ्रेमवर्क इन ऑपरेटरों की परवाह नहीं करता है, यह केवल कुछ Equalsतरीकों की परवाह करता है । उपयोगकर्ता द्वारा अग्रानुक्रम में परिभाषित किए जाने वाले = = और! = दोनों संचालकों की आवश्यकता का निर्णय विशुद्ध रूप से भाषा के डिजाइन से संबंधित है और वस्तु शब्दार्थों का नहीं जहां तक ​​.NET का संबंध है।


24
एक उत्कृष्ट प्रश्न के लिए +1। वहाँ बिल्कुल भी कोई कारण नहीं लगता है ... बेशक संकलक मान सकता है कि a =! B का अनुवाद किया जा सकता है! ((A ==) जब तक कि इसे अन्यथा न बताया जाए। मैं यह जानने के लिए उत्सुक हूं कि उन्होंने ऐसा करने का फैसला क्यों किया।
पैट्रिक87

16
यह सबसे तेज़ है जिसे मैंने एक प्रश्न पर वोट दिया और देखा है।
क्रिस्टोफर Currens

26
मुझे यकीन है कि @ Eric Lippert ध्वनि उत्तर भी दे सकता है।
युक

17
"वैज्ञानिक एक ऐसा व्यक्ति नहीं है जो सही उत्तर देता है, वह वह है जो सही प्रश्न पूछता है"। यही कारण है कि एसई में, प्रश्नों को प्रोत्साहित किया जाता है। और यह काम करता है!
एड्रियानो कारनेइरो

4
अजगर के लिए एक ही सवाल: stackoverflow.com/questions/4969629/…
जोश ली

जवाबों:


161

मैं भाषा डिजाइनरों के लिए नहीं बोल सकता, लेकिन मैं जिस पर तर्क कर सकता हूं, ऐसा लगता है कि यह जानबूझकर, उचित डिजाइन निर्णय था।

इस मूल F # कोड को देखते हुए, आप इसे एक कार्यशील पुस्तकालय में संकलित कर सकते हैं। यह F # के लिए कानूनी कोड है, और केवल समानता ऑपरेटर को ओवरलोड करता है, असमानता को नहीं:

module Module1

type Foo() =
    let mutable myInternalValue = 0
    member this.Prop
        with get () = myInternalValue
        and set (value) = myInternalValue <- value

    static member op_Equality (left : Foo, right : Foo) = left.Prop = right.Prop
    //static member op_Inequality (left : Foo, right : Foo) = left.Prop <> right.Prop

यह ठीक वैसा ही करता है जैसा दिखता है। यह ==केवल पर एक समानता तुलना बनाता है , और यह देखने के लिए जाँचता है कि क्या वर्ग के आंतरिक मूल्य समान हैं।

जब आप C # में इस तरह की क्लास नहीं बना सकते हैं , तो आप .NET के लिए संकलित एक का उपयोग कर सकते हैं। यह स्पष्ट है कि यह हमारे अतिभारित ऑपरेटर का उपयोग करेगा == तो, रनटाइम के लिए क्या उपयोग करता है !=?

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

यह जानते हुए कि यह मामला है, असली सवाल यह है कि यह इस तरह से क्यों बनाया गया था और संकलक इसे अपने आप ही बाहर क्यों नहीं करता है? बहुत से लोग कह रहे हैं कि यह एक डिजाइन निर्णय नहीं था, लेकिन मुझे लगता है कि यह इस तरह से सोचा गया था, खासकर इस तथ्य के बारे में कि सभी वस्तुओं में एक डिफ़ॉल्ट समानता ऑपरेटर होता है।

तो, संकलक स्वचालित रूप से !=ऑपरेटर क्यों नहीं बनाता है ? जब तक Microsoft का कोई व्यक्ति इस बात की पुष्टि नहीं करता, मैं निश्चित रूप से नहीं जान सकता, लेकिन यह वही है जो मैं तथ्यों पर तर्क से निर्धारित कर सकता हूं।


अप्रत्याशित व्यवहार को रोकने के लिए

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

आपको इसे ओवरलोड करने के लिए मजबूर करने के संदर्भ में , डिफ़ॉल्ट व्यवहार पर जाने के बजाय, मैं केवल दृढ़ता से कह सकता हूं कि यह मानक (EMCA-334 17.9.2) 2 में है । मानक क्यों निर्दिष्ट नहीं करता है। मेरा मानना ​​है कि यह इस तथ्य के कारण है कि C # C ++ से अधिक व्यवहार उधार लेता है। इस पर अधिक जानकारी के लिए नीचे देखें।


जब आप ओवरराइड करते हैं !=और ==, आपको बूल वापस नहीं करना है।

यह एक और संभावित कारण है। C # में, यह फ़ंक्शन:

public static int operator ==(MyClass a, MyClass b) { return 0; }

यह इस रूप में मान्य है:

public static bool operator ==(MyClass a, MyClass b) { return true; }

यदि आप बूल के अलावा कुछ वापस कर रहे हैं, तो संकलक स्वचालित रूप से एक विपरीत प्रकार का अनुमान नहीं लगा सकता है । इसके अलावा, उस मामले में जहां आपका ऑपरेटर है करता वापसी bool, यह सिर्फ भावना उन्हें कोड है कि है कि एक विशेष मामले में मौजूद केवल हैं उत्पन्न बनाने के लिए के रूप में मैं ऊपर कहा नहीं है या,, कोड है कि खाल CLR के डिफ़ॉल्ट व्यवहार।


C # C ++ से बहुत अधिक उधार लेता है 3

जब C # पेश किया गया था, तब MSDN पत्रिका में एक लेख था, जिसमें C # के बारे में बात करते हुए लिखा गया था:

कई डेवलपर्स चाहते हैं कि एक ऐसी भाषा थी जो विज़ुअल बेसिक की तरह लिखना, पढ़ना और बनाए रखना आसान था, लेकिन फिर भी यह C ++ की शक्ति और लचीलापन प्रदान करता है।

हां C # के लिए डिज़ाइन लक्ष्य, C ++ की लगभग समान शक्ति देना था, जो कि कठोर प्रकार-सुरक्षा और कचरा-संग्रह जैसी उपयुक्तता के लिए केवल थोड़ा त्याग कर रहा था। C ++ के बाद C # का जोरदार मॉडल तैयार किया गया।

आपको यह जानकर आश्चर्य नहीं हो सकता है कि सी ++ में, समानता ऑपरेटरों को बूल वापस नहीं करना है , जैसा कि इस उदाहरण कार्यक्रम में दिखाया गया है

अब, C ++ को सीधे पूरक ऑपरेटर को अधिभारित करने की आवश्यकता नहीं है । यदि आपका कोड उदाहरण कार्यक्रम में कोड संकलित करता है, तो आप देखेंगे कि यह बिना किसी त्रुटि के चलता है। हालाँकि, यदि आपने लाइन जोड़ने की कोशिश की है:

cout << (a != b);

तुम्हे मिल जाएगा

संकलक त्रुटि C2678 (MSVC): बाइनरी '! =': कोई ऑपरेटर नहीं मिला, जो 'टेस्ट' (या कोई स्वीकार्य रूपांतरण नहीं है) के बाएं हाथ के ऑपरेंड लेता है।

इसलिए, जबकि C ++ को आपको जोड़े में ओवरलोड करने की आवश्यकता नहीं है, यह आपको एक समानता ऑपरेटर का उपयोग नहीं करने देगा जिसे आपने कस्टम वर्ग पर अधिभारित नहीं किया है। यह .NET में मान्य है, क्योंकि सभी वस्तुओं में एक डिफ़ॉल्ट है; C ++ नहीं करता है।


1. एक साइड नोट के रूप में, सी # मानक अभी भी आपको ऑपरेटरों की जोड़ी को ओवरलोड करने की आवश्यकता है यदि आप किसी एक को अधिभार देना चाहते हैं। यह मानक का एक हिस्सा है और केवल संकलक नहीं है । हालाँकि, जब आप किसी अन्य भाषा में लिखी गई .net लाइब्रेरी तक पहुँच प्राप्त कर रहे हैं, तो उसी नियम की आवश्यकता नहीं है, जिस ऑपरेटर को कॉल करने के लिए निर्धारित किया जाता है।

2. EMCA-334 (पीडीएफ) ( http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf )

3. और जावा, लेकिन यह वास्तव में यहाँ बात नहीं है


75
" आपको बूल वापस नहीं करना है " .. मुझे लगता है कि हमारा जवाब वहीं है; बहुत बढ़िया। यदि (o1 == o2) भी अच्छी तरह से परिभाषित नहीं है, तो आप मानक पर भरोसा करने की उम्मीद नहीं कर सकते।
ब्रायन गॉर्डन

10
तार्किक रूप से तार्किक संचालकों के बारे में विडंबना यह है कि आपने वाक्य में एक डबल-नकारात्मक का उपयोग किया है, "C # आपको केवल किसी एक को ओवरराइड नहीं करने देता है" जिसका वास्तव में तार्किक अर्थ है "C # आपको केवल किसी एक को ओवरराइड करने की अनुमति देता है"।
दान डिप्लो

13
@ डान्लो, यह ठीक है, ऐसा नहीं है कि मैं ऐसा नहीं करने के लिए निषिद्ध नहीं हूं।
क्रिस्टोफर Currens

6
अगर सच है, मुझे संदेह है # 2 सही है; लेकिन अब सवाल यह है कि ==कुछ भी वापस करने की अनुमति क्यों bool? यदि आप वापस लौटते हैं int, तो आप इसे सशर्त विवरण के रूप में उपयोग नहीं कर सकते हैं। if(a == b)अब संकलन नहीं होगा। क्या बात है?
ब्लूराजा - डैनी Pflughoeft

2
आप एक ऐसी वस्तु लौटा सकते हैं, जिसका बूल (ऑपरेटर सही / गलत) में निहित रूपांतरण है, लेकिन मैं अभी भी यह देखने में विफल हूं कि यह कहां उपयोगी होगा।
स्टीफन ड्रैगनेव

53

शायद के लिए किसी को तीन-मूल्यवान तर्क (यानी null ) । उदाहरण के लिए, एएनएसआई मानक एसक्यूएल जैसे मामलों में - ऑपरेटरों को इनपुट के आधार पर केवल नकारा नहीं जा सकता है।

आपके पास एक मामला हो सकता है:

var a = SomeObject();

और a == trueरिटर्न falseऔर a == falseभी रिटर्न false


1
मैं उस मामले में कहूंगा, चूंकि aएक बूलियन नहीं है, जिसकी तुलना आपको एक तीन-राज्य एनम के साथ की जानी चाहिए, वास्तविक trueया नहीं false
ब्रायन गॉर्डन

18
वैसे, मैं विश्वास नहीं कर सकता कि किसी ने भी FileNotFound चुटकुले का जिक्र नहीं किया है ..
ब्रायन गॉर्डन

28
अगर a == trueहै falseतो मैं हमेशा उम्मीद करेंगे a != trueहोने के लिए true, के बावजूद a == falseकिया जा रहा हैfalse
Fede

20
@ फ़ेड ने कील को सिर पर मारा। यह वास्तव में इस सवाल से कोई लेना-देना नहीं है - आप समझा रहे हैं कि कोई व्यक्ति ओवरराइड ==क्यों करना चाहता है , न कि क्यों उन्हें दोनों को ओवरराइड करने के लिए मजबूर किया जाना चाहिए।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

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

25

कई क्षेत्रों में उस सी # डिफाल्टर्स के अलावा, सी ++ के लिए सबसे अच्छा विवरण, जो मैं सोच सकता हूं वह यह है कि कुछ मामलों में आप थोड़ा लेना चाह सकते हैं "समानता" को साबित करने की तुलना में "समानता नहीं" साबित करने के लिए अलग दृष्टिकोण ।

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


6
महान उदाहरण; मुझे लगता है कि आप इस कारण पर हैं। एक साधारण !आपको समानता के लिए एकल परिभाषा में बंद करता है, जहां एक सूचित कोडर दोनों को अनुकूलित करने में सक्षम हो सकता है ==और !=
Yuck

13
इसलिए यह बताता है कि क्यों उन्हें दोनों को ओवरराइड करने का विकल्प दिया जाना चाहिए , न कि उन्हें क्यों मजबूर किया जाना चाहिए ।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

1
उस नस में, उन्हें दोनों को अनुकूलित करने की आवश्यकता नहीं है , उन्हें बस दोनों की स्पष्ट परिभाषा प्रदान करनी है ।
जेसपर

22

यदि आप .net स्रोत में == और! = के अधिभार के कार्यान्वयन को देखते हैं, तो वे अक्सर लागू नहीं करते हैं! = जैसा (! बाएं == दाएं)। वे इसे पूरी तरह से (जैसे ==) नकारात्मक तर्क के साथ लागू करते हैं। उदाहरण के लिए, DateTime लागू = = के रूप में

return d1.InternalTicks == d2.InternalTicks;

और = = जैसा

return d1.InternalTicks != d2.InternalTicks;

यदि आप (या संकलक अगर यह निहित है) को लागू करने के लिए थे! = As

return !(d1==d2);

तब आप उन चीजों के बारे में एक धारणा बना रहे हैं जो आपकी कक्षा को संदर्भित कर रही हैं। इस निर्णय से बचने के पीछे उनके निर्णय का दर्शन हो सकता है।


17

अपने संपादन का उत्तर देने के लिए, इस बारे में कि आप दोनों को ओवरराइड करने के लिए क्यों मजबूर किया जाता है यदि आप एक को ओवरराइड करते हैं, तो यह सब विरासत में है।

यदि आप == को ओवरराइड करते हैं, तो कुछ प्रकार के शब्दार्थ या संरचनात्मक समानता प्रदान करने की संभावना है (उदाहरण के लिए, डेटटाइम्स बराबर हैं यदि उनके आंतरिक गुण समान हैं, भले ही वे अलग-अलग उदाहरण हो सकते हैं), तो आप ऑपरेटर के डिफ़ॉल्ट व्यवहार को बदल रहे हैं ऑब्जेक्ट, जो सभी .NET ऑब्जेक्ट्स का पैरेंट है। == ऑपरेटर, C # में है, एक विधि, जिसका आधार कार्यान्वयन Object.operator (==) एक संदर्भात्मक तुलना करता है। Object.operator (! =) एक और, अलग विधि है, जो एक संदर्भात्मक तुलना भी करती है।

ओवरराइड करने की विधि के लगभग किसी भी अन्य मामले में, यह मान लेना अतार्किक होगा कि किसी एक विधि को ओवरराइड करने से भी एनाटॉमिक पद्धति में व्यवहार परिवर्तन हो जाएगा। यदि आपने एक बच्चे की कक्षा में इंक्रीमेंट () और डिक्रीमेंट () के तरीके, और ओवररोड इन्क्रीमेंट () के साथ एक वर्ग बनाया है, तो क्या आप डिक्रिमेंट () से भी अपेक्षा करेंगे कि वह आपके ओवरराइड व्यवहार के विपरीत होने पर भी ओवरराइड हो जाए? सभी संभावित मामलों में ऑपरेटर के किसी भी कार्यान्वयन के लिए उलटा कार्य उत्पन्न करने के लिए कंपाइलर को पर्याप्त स्मार्ट नहीं बनाया जा सकता है।

हालांकि, ऑपरेटरों, हालांकि तरीकों से बहुत समान रूप से लागू होते हैं, जोड़े में वैचारिक रूप से काम करते हैं; == और = =, <और>, और <= और> =। यह सोचना उपभोक्ता के दृष्टिकोण से इस मामले में अतार्किक होगा! = किसी भी तरह से == से अलग काम किया। इसलिए, कंपाइलर को यह मानने के लिए नहीं बनाया जा सकता है कि सभी मामलों में a =! B ==! (A == b), लेकिन आमतौर पर यह अपेक्षा की जाती है कि == और! = समान शैली में काम करना चाहिए, इसलिए संकलक बल आप जोड़े में लागू करने के लिए, हालांकि आप वास्तव में ऐसा कर रहे हैं। यदि, आपकी कक्षा के लिए, (=! B ==! (A ==), तो बस (! =) का उपयोग करके ऑपरेटर लागू करें (==), लेकिन यदि वह नियम आपकी वस्तु के लिए सभी मामलों में नहीं है (उदाहरण के लिए) , यदि एक विशेष मूल्य के साथ तुलना, समान या असमान, मान्य नहीं है), तो आपको आईडीई से अधिक चालाक होना होगा।

REAL सवाल जो पूछा जाना चाहिए कि क्यों <और> और <= और> = तुलनात्मक ऑपरेटरों के लिए जोड़े हैं जो समवर्ती रूप से लागू किए जाने चाहिए, जब संख्यात्मक शब्दों में! (A <b) == a> = b और! (A) b) == ए <= बी। यदि आप एक को ओवरराइड करते हैं, तो आपको सभी चार को लागू करने की आवश्यकता होनी चाहिए, और आपको संभवतः ओवरराइड == (और! =) के रूप में अच्छी तरह से करना चाहिए, क्योंकि यदि एक शब्दार्थ है तो (a <= b) == (a = b) ब के बराबर।


14

यदि आप अपने कस्टम प्रकार के लिए == ओवरलोड करते हैं, और नहीं! = तो इसे ऑब्जेक्ट द्वारा संभाला जाएगा! = ऑब्जेक्ट के लिए ऑपरेटर! = ऑब्जेक्ट चूंकि सब कुछ ऑब्जेक्ट से प्राप्त होता है, और यह CustomType! = CustomType से बहुत भिन्न होगा।

साथ ही भाषा निर्माता शायद यह चाहते थे कि यह कोडर्स के लिए सबसे अधिक लचीलेपन की अनुमति दे, और यह भी कि वे इस बारे में धारणा नहीं बना रहे हैं कि आप क्या करने का इरादा रखते हैं।


आपने इस प्रश्न को प्रेरित किया: stackoverflow.com/questions/6919259/…
ब्रायन गॉर्डन

2
लचीलेपन के कारण को कई महान विशेषताओं पर भी लागू किया जा सकता है, जिन्हें उन्होंने छोड़ने का फैसला किया, उदाहरण के लिए blogs.msdn.com/b/ericlippert/archive/2011/06/23/…। या तो यह उनकी पसंद की व्याख्या नहीं करता है। समानता ऑपरेटरों के कार्यान्वयन।
स्टीफन ड्रैगनेव

यह एक बहुत ही दिलचस्प है। ऐसा लगता है कि यह एक उपयोगी विशेषता होगी। मुझे नहीं पता कि उन्होंने उस एक को क्यों छोड़ा होगा।
क्रिस मुलिंस

11

यह मेरे दिमाग में सबसे पहले आता है:

  • क्या होगा अगर समानता को परखने की तुलना में परीक्षण असमानता बहुत तेज है?
  • क्या होगा अगर कुछ मामलों में आप falseदोनों को वापस करना चाहते हैं==!= ( और यदि किसी कारण से उनकी तुलना नहीं की जा सकती)

5
पहले मामले में आप असमानता परीक्षण के संदर्भ में समानता परीक्षण लागू कर सकते थे।
स्टीफन ड्रैगनेव

दूसरा मामला संरचनाओं को तोड़ देगा Dictionaryऔर Listयदि आप उनके साथ अपने कस्टम प्रकार का उपयोग करते हैं।
स्टीफन ड्रैगनेव

2
@Stefan: ऑपरेटरों Dictionaryका उपयोग करता है GetHashCodeऔर Equalsनहीं। Listका उपयोग करता है Equals
दान Abramov 20

6

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

C # और Lua के बीच कुछ अन्य अंतर भी हो सकते हैं ...


1
एक दूसरे के संदर्भ में इसे लागू करना उत्कृष्ट अभ्यास है। मैंने अभी इसे अन्यथा किया है - जो त्रुटि प्रवण है।
स्टीफन ड्रैगनेव

3
यह प्रोग्रामर की समस्या है, C # की समस्या नहीं है। प्रोग्रामर जो इस अधिकार को लागू करने में विफल होते हैं, वे अन्य क्षेत्रों में भी असफल होंगे।
GolezTrol

@GolezTrol: क्या आप समझा सकते हैं कि लुआ संदर्भ? मैं लूआ से बिल्कुल परिचित नहीं हूं, लेकिन आप संदर्भ कुछ पर इशारा करते हैं।
zw324

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

6

आपके प्रश्न में मुख्य शब्द " क्यों " और " होना चाहिए " हैं।

नतीजतन:

इसका उत्तर इस तरह से है क्योंकि उन्होंने इसे ऐसा करने के लिए डिज़ाइन किया है, यह सच है ... लेकिन आपके प्रश्न का "क्यों" हिस्सा नहीं है।

यह उत्तर देना कि यह कभी-कभी इन दोनों को स्वतंत्र रूप से ओवरराइड करने में सहायक हो सकता है, सच है ... लेकिन आपके प्रश्न के "आवश्यक" भाग का उत्तर नहीं दे रहा है।

मुझे लगता है कि सरल उत्तर यह है कि सी # की कोई ठोस वजह नहीं है कि आपको दोनों को ओवरराइड करने की आवश्यकता हो।

भाषा आप केवल ओवरराइड करने की अनुमति चाहिए ==, और आप की एक डिफ़ॉल्ट कार्यान्वयन प्रदान !=करता है !कि। यदि आप के !=रूप में अच्छी तरह से ओवरराइड करना चाहते हैं , तो उस पर है।

यह एक अच्छा निर्णय नहीं था। मनुष्य की डिजाइन भाषाएं, मनुष्य परिपूर्ण नहीं हैं, C # सही नहीं है। श्रग और QED


5

बस यहाँ उत्कृष्ट उत्तरों को जोड़ने के लिए:

विचार करें कि डिबगर में क्या होगा , जब आप एक !=ऑपरेटर में कदम रखने और एक में समाप्त होने की कोशिश करेंगे== इसके बजाय ऑपरेटर ! भ्रमित करने वाली बात!

यह समझ में आता है कि सीएलआर आपको एक या अन्य ऑपरेटरों को छोड़ने की स्वतंत्रता देगा - क्योंकि यह कई भाषाओं के साथ काम करना चाहिए। लेकिन सी # CLR सुविधाओं को उजागर नहीं (के उदाहरण के बहुत देखते हैं ref(: जैसे रिटर्न और स्थानीय लोगों को, उदाहरण के लिए), और सुविधाओं CLR अपने आप में नहीं लागू करने के उदाहरण के बहुत सारे using, lock, foreach, आदि)।


3

प्रोग्रामिंग भाषा असाधारण जटिल तार्किक कथन के वाक्यविन्यास पुनर्व्यवस्था हैं। मन में, क्या आप गैर-बराबरी के मामले को परिभाषित किए बिना समानता के मामले को परिभाषित कर सकते हैं? जवाब न है। किसी वस्तु के लिए वस्तु b के बराबर होना चाहिए, तो ऑब्जेक्ट का व्युत्क्रम b नहीं के बराबर होना भी सत्य होना चाहिए। इसे दिखाने का एक और तरीका है

if a == b then !(a != b)

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

अब, के विचार के संबंध में! = बस के रूप में बदली जा रही परिभाषा में

if !(a==b) then a!=b

मैं इसके साथ बहस नहीं कर सकता। हालाँकि, C # भाषा विनिर्देश समूह द्वारा यह सबसे अधिक संभावना था कि प्रोग्रामर को किसी वस्तु की समानता और गैर-समानता को स्पष्ट रूप से परिभाषित करने के लिए मजबूर किया जाए।


Nullकेवल एक समस्या हो सकती है क्योंकि nullएक वैध इनपुट है ==, जिसे यह नहीं होना चाहिए, हालांकि जाहिर है, यह बड़े पैमाने पर सुविधाजनक है। निजी तौर पर, मुझे लगता है कि यह विशाल मात्रा में अस्पष्ट, मैला प्रोग्रामिंग के लिए अनुमति देता है।
निकोडेमस 13

2

संक्षेप में, मजबूर स्थिरता।

'==' और '! =' हमेशा सच्चे विपरीत होते हैं, चाहे आप उन्हें कैसे भी परिभाषित करें, "मौखिक" और "समान नहीं" की उनकी मौखिक परिभाषा के अनुसार परिभाषित किया गया है। उनमें से केवल एक को परिभाषित करके, आप अपने आप को एक समानता ऑपरेटर असंगतता के लिए खोलते हैं जहां दोनों '==' और '! =' दोनों सत्य हो सकते हैं या दोनों दिए गए मूल्यों के लिए दोनों झूठे हो सकते हैं। आप दोनों को तब से परिभाषित करते हैं जब आप एक को परिभाषित करने के लिए चुनते हैं, तो आपको दूसरे को भी उचित रूप से परिभाषित करना होगा ताकि यह स्पष्ट रूप से स्पष्ट हो जाए कि आपकी "समानता" की परिभाषा क्या है। संकलक के लिए अन्य समाधान केवल आपको '==' या '! =' को ओवरराइड करने की अनुमति है और दूसरे को स्वाभाविक रूप से नकारने के रूप में छोड़ दें। जाहिर है, कि सी # संकलक के साथ ऐसा नहीं है और मुझे यकीन है कि वहाँ '

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

अन्त में, IEquatable () एक ही तर्क के लिए NotEquals () को परिभाषित नहीं करता है: समानता ऑपरेटर विसंगतियों को खोलने की क्षमता। NotEquals () हमेशा वापस आना चाहिए! बराबर ()। बराबर लागू करने वाले वर्ग को NotEquals () की परिभाषा को खोलकर, आप एक बार फिर समानता का निर्धारण करने में स्थिरता के मुद्दे को मजबूर कर रहे हैं।

संपादित करें: यह केवल मेरा तर्क है।


यह अतार्किक है। यदि कारण सुसंगतता था तो विपरीत लागू होगा: आप केवल लागू करने में सक्षम होंगे operator ==और संकलक अनुमान लगाएगा operator !=। आखिरकार, यह वही है जो इसके लिए करता है operator +और operator +=
कोनराड रुडोल्फ

1
फू + = बार; एक मिश्रित कार्य है, फू = फू + बार के लिए आशुलिपि; यह कोई ऑपरेटर नहीं है।
ब्लेंडरफ्रीकी

वे तो वास्तव में कर रहे हैं 'हमेशा सच विपरीत' है, तो है कि एक कारण हो सकता है करने के लिए स्वचालित रूप से परिभाषित a != bके रूप में !(a == b)(जो क्या नहीं सी # करता है) ...।
andrewf

-3

शायद सिर्फ कुछ वे नहीं सोचा था कि करने के लिए समय नहीं था।

ओवरलोड == होने पर मैं हमेशा आपके तरीके का उपयोग करता हूं। फिर मैं इसे दूसरे में उपयोग करता हूं।

आप सही हैं, काम की एक छोटी राशि के साथ, कंपाइलर हमें मुफ्त में दे सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.