मैं एक अनंत = पुनरावृत्ति के बिना '==' ऑपरेटर अधिभार में नल की जांच कैसे करूं?


113

निम्न == ऑपरेटर अधिभार विधि पर अनंत पुनरावृत्ति का कारण होगा

    Foo foo1 = null;
    Foo foo2 = new Foo();
    Assert.IsFalse(foo1 == foo2);

    public static bool operator ==(Foo foo1, Foo foo2) {
        if (foo1 == null) return foo2 == null;
        return foo1.Equals(foo2);
    }

मैं नलियों के लिए कैसे जांच करूं?

जवाबों:


138

उपयोग करें ReferenceEquals:

Foo foo1 = null;
Foo foo2 = new Foo();
Assert.IsFalse(foo1 == foo2);

public static bool operator ==(Foo foo1, Foo foo2) {
    if (object.ReferenceEquals(null, foo1))
        return object.ReferenceEquals(null, foo2);
    return foo1.Equals(foo2);
}

यह समाधान के लिए काम नहीं करता हैAssert.IsFalse(foo2 == foo1);
FIL

और क्या foo1.Equals(foo2)मतलब है अगर, उदाहरण के लिए, मैं foo1 == foo2केवल अगर चाहता हूँ foo1.x == foo2.x && foo1.y == foo2.y? क्या यह जवाब मामले की अनदेखी नहीं है, foo1 != nullलेकिन foo2 == nullकहां है?
डैनियल

नोट: सरल सिंटैक्स के साथ एक ही समाधान:if (foo1 is null) return foo2 is null;
रेम

20

अधिभार विधि में ऑब्जेक्ट कास्ट करें:

public static bool operator ==(Foo foo1, Foo foo2) {
    if ((object) foo1 == null) return (object) foo2 == null;
    return foo1.Equals(foo2);
}

1
बिल्कुल सही। दोनों (object)foo1 == nullया foo1 == (object)nullके लिए जाना जाएगा निर्मित अधिभार ==(object, object)और नहीं उपयोगकर्ता परिभाषित अधिभार के लिए ==(Foo, Foo)। यह सिर्फ तरीकों पर अधिभार संकल्प की तरह है।
जेपी स्टिग नीलसन

2
भविष्य के आगंतुकों के लिए - स्वीकृत उत्तर एक फ़ंक्शन है, जो ऑब्जेक्ट के == को निष्पादित करता है। यह मूल रूप से स्वीकृत उत्तर के समान है, एक नकारात्मक पक्ष के साथ: इसे एक डाली की आवश्यकता है। इस प्रकार उत्तर दिया गया उत्तर श्रेष्ठ है।
माफिया जूल

1
@Mafii कास्ट शुद्ध रूप से एक संकलन समय ऑपरेशन है। चूंकि कंपाइलर जानता है कि कास्ट विफल नहीं हो सकता है, उसे रनटाइम पर कुछ भी जांचने की आवश्यकता नहीं है। विधियों के बीच अंतर पूरी तरह से सौंदर्यवादी हैं।
सेवाकाल


4

प्रयत्न Object.ReferenceEquals(foo1, null)

वैसे भी, मैं ==ऑपरेटर को ओवरलोड करने की सलाह नहीं दूंगा ; इसका उपयोग संदर्भों की तुलना करने के लिए किया जाना चाहिए, और Equals"सिमेंटिक" तुलनाओं के लिए उपयोग किया जाना चाहिए ।


4

यदि मैंने ओवरराइड किया है bool Equals(object obj)और मैं चाहता हूं कि ऑपरेटर ==और Foo.Equals(object obj)उसी मूल्य को लौटाए, तो मैं आमतौर पर !=ऑपरेटर को इस तरह लागू करता हूं :

public static bool operator ==(Foo foo1, Foo foo2) {
  return object.Equals(foo1, foo2);
}
public static bool operator !=(Foo foo1, Foo foo2) {
  return !object.Equals(foo1, foo2);
}

ऑपरेटर ==तब मेरे लिए सभी शून्य चेक करने के बाद कॉल करेगा foo1.Equals(foo2)कि मैंने वास्तविक चेक करने के लिए ओवरराइड किया है अगर दोनों समान हैं।


यह बहुत उचित लगता है; Object.Equals(Object, Object)साथ-साथ लागू होने को देखते हुए Object.ReferenceEquals(Object, Object), यह बहुत स्पष्ट है कि Object.Equals(Object, Object)बॉक्स के बाहर अन्य उत्तरों में सुझाए गए अनुसार सब कुछ करता है। इसका उपयोग क्यों नहीं करते?
tne

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

@ मुझे विश्वास है कि आपने मेरी टिप्पणी को गलत समझा; एक संदर्भ में जहां यह पहले से ही स्थापित है कि अतिभार ==वांछनीय है (प्रश्न इसका अर्थ है) मैं बस इस उत्तर का समर्थन कर रहा हूं जो सुझाव Object.Equals(Object, Object)देता है कि अन्य चालें जैसे कि ReferenceEqualsस्पष्ट या स्पष्ट कास्ट का उपयोग करना अनावश्यक है (इस प्रकार "क्यों नहीं इसका उपयोग करें?", "यह" जा रहा है Equals(Object, Object))। यहां तक ​​कि अगर असंबंधित आपकी बात भी सही है, और मैं आगे बढ़ूंगा: केवल ==उन वस्तुओं के लिए अधिभार जो हम "मूल्य वस्तुओं" के रूप में वर्गीकृत कर सकते हैं।
tne

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

@tne वर्चुअल विधि कॉल को अनुकूलित करने की जटिलताओं के बारे में अधिक जानकारी के लिए, stackoverflow.com/questions/530799/… देखें ।
दान बेखार्ड

3

यदि आप C # 7 का उपयोग कर रहे हैं या बाद में आप अशक्त निरंतर पैटर्न मिलान का उपयोग कर सकते हैं:

public static bool operator==(Foo foo1, Foo foo2)
{
    if (foo1 is null)
        return foo2 is null;
    return foo1.Equals(foo2);
}

यह आपको एक कॉलिंग ऑब्जेक्ट की तुलना में थोड़ा नटेरटर कोड देता है। संदर्भ (foo1, null)


2
याpublic static bool operator==( Foo foo1, Foo foo2 ) => foo1?.Equals( foo2 ) ?? foo2 is null;
डेंको डर्बिएक

3

वास्तव nullमें इस मामले में जाँच का एक सरल तरीका है :

if (foo is null)

बस!

इस फीचर को C # 7 में पेश किया गया था


1

मेरा दृष्टिकोण क्या करना है

(object)item == null

जिस पर मैं objectखुद की समानता ऑपरेटर पर भरोसा कर रहा हूं जो गलत नहीं हो सकता। या एक कस्टम एक्सटेंशन विधि (और एक अधिभार):

public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null;
}

public static bool IsNull<T>(this T? obj) where T : struct
{
    return !obj.HasValue;
}

या अधिक मामलों को संभालने के लिए, हो सकता है:

public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null || obj == DBNull.Value;
}

बाधा IsNullमूल्य के प्रकारों को रोकती है । अब यह कॉलिंग जितना मीठा है

object obj = new object();
Guid? guid = null; 
bool b = obj.IsNull(); // false
b = guid.IsNull(); // true
2.IsNull(); // error

जिसका अर्थ है कि मेरे पास नल के लिए जाँच करने की एक सुसंगत / नहीं-त्रुटि-प्रवण शैली है। मैंने यह भी पाया (object)item == nullहैObject.ReferenceEquals(item, null) कि यह बहुत कम की तुलना में बहुत तेजी से है , लेकिन केवल अगर यह मायने रखता है (मैं वर्तमान में कुछ पर काम कर रहा हूं, जहां मैंने सब कुछ सूक्ष्म रूप से अनुकूलित किया है!)।

समानता चेक लागू करने पर एक संपूर्ण मार्गदर्शिका देखने के लिए, संदर्भ प्रकार के दो उदाहरणों की तुलना करने के लिए "सर्वश्रेष्ठ अभ्यास" क्या है?


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

0

स्थिर Equals(Object, Object)विधि इंगित करती है कि क्या दो वस्तुएं, objAऔर objB, समान हैं। यह आपको उन वस्तुओं का परीक्षण करने में भी सक्षम बनाता है जिनका मूल्य nullसमानता के लिए है। यह तुलना objAऔर objBसमानता के लिए निम्नानुसार है:

  • यह निर्धारित करता है कि क्या दो वस्तुएं एक ही वस्तु संदर्भ का प्रतिनिधित्व करती हैं। यदि वे करते हैं, तो विधि वापस आ जाती है true। यह परीक्षण ReferenceEqualsविधि को कॉल करने के बराबर है । इसके अलावा, यदि दोनों objAऔर objBहैं null, तो विधि वापस आ जाती है true
  • यह निर्धारित करता है कि या तो objAया objBहै null। यदि हां, तो यह वापस आ जाता है false। यदि दो ऑब्जेक्ट एक ही ऑब्जेक्ट संदर्भ का प्रतिनिधित्व नहीं करते हैं और न ही है null, तो यह कॉल करता है objA.Equals(objB)और परिणाम देता है। इसका मतलब यह है कि यदि विधि को objAओवरराइड करता Object.Equals(Object)है, तो यह ओवरराइड कहा जाता है।

public static bool operator ==(Foo objA, Foo objB) {
    return Object.Equals(objA, objB);
}

0

ओवरराइडिंग ऑपरेटर को अधिक जवाब देने के लिए कि शून्य की तुलना कैसे करें, जो यहां डुप्लिकेट के रूप में रीडायरेक्ट करता है।

ऐसे मामलों में जहां यह वैल्यू ऑब्जेक्ट्स को सपोर्ट करने के लिए किया जा रहा है, मुझे लगता है कि नए नोटेशन को काम करना है, और यह सुनिश्चित करना पसंद है कि केवल एक ही जगह है जहां तुलना की जाती है। ऑब्जेक्ट का लाभ भी ले रहा है। Equals (A, B) नल जांच को सरल करता है।

यह ==, =! = के बराबर होगा, और GetHashCode

    public static bool operator !=(ValueObject self, ValueObject other) => !Equals(self, other);
    public static bool operator ==(ValueObject self, ValueObject other) => Equals(self, other);
    public override bool Equals(object other) => Equals(other as ValueObject );
    public bool Equals(ValueObject other) {
        return !(other is null) && 
               // Value comparisons
               _value == other._value;
    }
    public override int GetHashCode() => _value.GetHashCode();

अधिक जटिल वस्तुओं के लिए इक्वाल्स और एक अमीर GetHashCode में अतिरिक्त तुलनाएं जोड़ें।


0

एक आधुनिक और संघनित वाक्य रचना के लिए:

public static bool operator ==(Foo x, Foo y)
{
    return x is null ? y is null : x.Equals(y);
}

public static bool operator !=(Foo x, Foo y)
{
    return x is null ? !(y is null) : !x.Equals(y);
}

-3

ऑपरेटर के भार के में एक सामान्य त्रुटि == उपयोग करने के लिए है (a == b), (a ==null)या (b == null)संदर्भ समानता के लिए जाँच करने के लिए। यह बजाय में परिणाम है , अतिभारित ऑपरेटर == के लिए एक कॉल एक पैदा कर रहा infinite loopReferenceEqualsलूप से बचने के लिए ऑब्जेक्ट को टाइप करें या कास्ट करें ।

इसकी जांच करो

// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))// using ReferenceEquals
{
    return true;
}

// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))// using casting the type to Object
{
    return false;
}

ओवरलोडिंग बराबरी () और ऑपरेटर == के लिए संदर्भ दिशानिर्देश


1
इस जानकारी के सभी के साथ पहले से ही कई उत्तर हैं। हमें उसी उत्तर की 7 वीं प्रति की आवश्यकता नहीं है।
13

-5

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

public static bool operator ==(Foo foo1, Foo foo2)
{
    //  check if the left parameter is null
    bool LeftNull = false;
    try { Type temp = a_left.GetType(); }
    catch { LeftNull = true; }

    //  check if the right parameter is null
    bool RightNull = false;
    try { Type temp = a_right.GetType(); }
    catch { RightNull = true; }

    //  null checking results
    if (LeftNull && RightNull) return true;
    else if (LeftNull || RightNull) return false;
    else return foo1.field1 == foo2.field2;
}

यदि आपके पास कई अशक्त वस्तुएं हैं, तो अपवाद हैंडलिंग एक बड़ा ओवरहेड हो सकता है।
कास्परज़ोल

2
हाहा, मैं मानता हूं कि यह सबसे अच्छा तरीका नहीं है। इस विधि को पोस्ट करने के बाद, मैंने तुरंत अपने वर्तमान प्रोजेक्ट को इसके बजाय ReferenceEquals का उपयोग करने के लिए संशोधित किया। हालाँकि, यह सबॉप्टीमल होने के बावजूद काम नहीं करता है, और इस प्रकार यह प्रश्न का एक वैध उत्तर है।
बजे द डिजिटल गेबगे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.