2010-07-07 6 views
37

सीखते समय .net (सी # द्वारा) मुझे ऑब्जेक्ट्स के बीच समानता की जांच करने के 5 तरीके मिले।समानता जांच के लिए 5 तरीके .net .. क्यों? और किस का उपयोग करना है?

  1. संदर्भ एक्वाल्स() विधि।
  2. आभासी बराबर() विधि। (System.Object)
  3. स्थिर बराबर() विधि।
  4. IEquatable इंटरफेस से बराबर विधि।
  5. तुलना ऑपरेटर ==।

मेरा प्रश्न है:

  1. क्यों इतने सारे बराबर() विधि तुलना ऑपरेटर के साथ देखते हैं?
  2. कौन सा आभासी बराबर() या IEquatable के बराबर() का उपयोग किया जा sholud .. (कहते हैं हम अपने ही संग्रह कक्षाओं का उपयोग करता है, तो)

उत्तर

26

1 - संदर्भ चेकों दो संदर्भ प्रकार चर (कक्षाएं, नहीं structs) एक ही स्मृति पता करने के लिए भेजा जाता है, तो बराबर होती है।

2 - आभासी बराबर() विधि चेकों दो वस्तुओं समतुल्य होते हैं।o1.Equals करने के लिए कॉल

var o1 = new TestClass{property1 = 1, property2 = 2} 
var o2 = new TestClass{property1 = 1, property2 = 2} 

हालांकि दो वस्तुओं TestClass का एक ही उदाहरण नहीं हैं,:

class TestClass{ 
    public int Property1{get;set} 
    public int Property2{get;set} 

    public override bool Equals(object obj) 
    { 
     if (obj.GetType() != typeof(TestClass)) 
      return false; 

     var convertedObj = (TestClass)obj; 

     return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2); 
    } 
} 

और आप उस वर्ग से 2 वस्तुओं का दृष्टांत: हमें कहते हैं कि तुम इस वर्ग करते हैं (ओ 2) सच हो जाएगा।

3 - स्थिर बराबर विधि जब वहाँ की जांच में एक शून्य मान है समस्याओं को संभालने के लिए प्रयोग किया जाता है। कुछ भी नहीं है क्योंकि O1 अंक

o1.Equals(o2); 

आप एक NullReferenceException मिल wil,: इस कल्पना कीजिए, उदाहरण के लिए:

TestClass o1 = null; 
var o2 = new TestClass{property1 = 1, property2 = 2} 

आप इस प्रयास करें। इस मुद्दे पता करने के लिए, आप यह करते हैं:

Object.Equals (O1, O2);

इस विधि अशक्त संदर्भ को संभालने के लिए तैयार किया जाता है।

4 - IEquatable इंटरफ़ेस नेट द्वारा प्रदान की जाती है तो तुम क्या करने की जरूरत नहीं है अपने बराबर विधि के अंदर डाले। संकलक पता चल गया है कि आप प्रकार आप समानता के लिए जाँच करने के लिए कोशिश कर रहे हैं के लिए एक कक्षा में इंटरफ़ेस को लागू किया है, तो यह Object.Equals (वस्तु) ओवरराइड से अधिक है कि विधि प्राथमिकता देंगे। उदाहरण के लिए:

class TestClass : IEquatable<TestClass> 
{ 
    public int Property1 { get; set; } 
    public int Property2 { get; set; } 

    public override bool Equals(object obj) 
    { 
     if (obj.GetType() != typeof(TestClass)) 
      return false; 

     var convertedObj = (TestClass)obj; 

     return (convertedObj.Property1 == this.Property1 && convertedObj.Property2 == this.Property2); 
    } 

    #region IEquatable<TestClass> Members 

    public bool Equals(TestClass other) 
    { 
     return (other.Property1 == this.Property1 && other.Property2 == this.Property2); 
    } 

    #endregion 
} 

अब अगर हम ऐसा करते हैं:

var o1 = new TestClass{property1 = 1, property2 = 2} 
var o2 = new TestClass{property1 = 1, property2 = 2} 
o1.Equals(o2); 

बुलाया विधि बराबर (TestClass), बराबर (वस्तु) से पहले है।

5 - == ऑपरेटर आमतौर पर ReferenceEquals रूप में एक ही मतलब है, यह जाँच करता है दो चर एक ही स्मृति पता को इंगित करता है, तो। गॉचा यह है कि इस ऑपरेटर को अन्य प्रकार के चेक करने के लिए ओवरराइड किया जा सकता है। तारों में, उदाहरण के लिए, यह जांचता है कि दो अलग-अलग उदाहरण बराबर हैं या नहीं।

+0

को लागू करने पर संदेह को हल करने के लिए उत्कृष्ट। उदाहरण वास्तव में मदद करते हैं, लेकिन आपके बिंदु 4 में एक टाइपो है जहां IEquatable.Equals अभी भी 'convertObj' – PaulG

+0

धन्यवाद पॉलजी का उपयोग करता है, यह अभी तय है! =] – mverardo

29

ReferenceEquals() विधि में से एक।

यह परीक्षण करने के लिए करता है, तो दिए गए दो चर बात एक ही वस्तु के लिए (प्रतीक संदर्भ) किया जाता है। यह सचमुच ((object)a) == ((object)b) के बराबर है। यदि आप तुलना ऑपरेटर (==) को ओवरराइड करते हैं तो ReferenceEquals डिफ़ॉल्ट व्यवहार तक पहुंचने का एक तरीका बनाए रखता है।

हालांकि, यदि आप किसी मान प्रकार (उदा। एक संरचना) से निपट रहे हैं तो यह will always return false है। ऐसा इसलिए है क्योंकि तुलना मूल्य प्रत्येक मान प्रकार को एक नई वस्तु में स्वाभाविक रूप से संदर्भ बराबर नहीं होंगे।


आभासी बराबर() विधि। (System.Object)

यह प्राथमिक तरीका शब्दार्थ (किसी भी प्रकार की) दो वस्तुओं की तुलना करने के लिए है। प्रत्येक वर्ग इसे चुनने के रूप में ओवरराइड करता है। डिफ़ॉल्ट रूप से यह एक सीएलआर कॉल (InternalEquals) के बराबर है जो मूल रूप से स्मृति संदर्भों की तुलना करता है।

नोट, यदि दो ऑब्जेक्ट Equals() के लिए GetHashCode()must be equal पर सत्य लौटते हैं तो नोट करें। हालांकि, यदि दो ऑब्जेक्ट्स के लिए हैश कोड मूल्य समकक्ष हैं (यानी obj1.GetHashCode() == obj2.GetHashCode()) यह का अर्थ है कि Equals() सत्य है।

आपका वर्ग आम तौर पर वर्ग उदाहरणों भेद करने के लिए एक साधन के रूप Equals और GetHashCode को लागू करना चाहिए, और इस या == ऑपरेटर (आदर्श दोनों) को लागू करना चाहिए अगर यह एक मान प्रकार है।

ध्यान दें, मूल्य प्रकारों के लिए डिफ़ॉल्ट Equals व्यवहार ValueType.Equals() जो अगर आप परावर्तक में देखने का है (या the MSDN description पढ़ें) दो मूल्य उदाहरणों के सदस्यों की तुलना करने के प्रतिबिंब का उपयोग करता है।


स्थिर बराबर() विधि।

यह return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB))) जहां प्रत्येक प्रकार के परीक्षण के लिए Object में बदल जाती है के बराबर है। मेरे परीक्षण से पता चलता है कि अधिभारित तुलना ऑपरेटर को अनदेखा कर दिया जाता है, लेकिन यदि 0 ऑब्जेक्ट शून्य नहीं हैं और समान संदर्भ नहीं हैं तो आपकी Equals विधि का उपयोग किया जाएगा। इस प्रकार, a.Equals(b) आवश्यक नहीं है object.Equals(a, b) (उन मामलों के लिए जहां ((object)a) == ((object)b) या या तो ए या बी शून्य है)।


IEquatable इंटरफ़ेस से विधि के बराबर है।

आईक्वाटेबल विशेष रूप से उसी वर्ग के उदाहरणों की तुलना करने के लिए आपके लिए एक तरीका प्रदान करता है। कहा कि अपने Equals विधि should be handling the behaviour the same way:

आप बराबर लागू हैं, तो आप भी आधार वर्ग Object.Equals (वस्तु) और GetHashCode की कार्यान्वयन ओवरराइड करना चाहिए ताकि उनके व्यवहार संगत है के साथ IEquatable.Equals विधि

Nevertheless you should implement IEquatable:

संभावना है कि एक वर्ग के वस्तुओं एक सरणी या एक सामान्य संग्रह वस्तु में संग्रहीत किया जाएगा संभाल करने के लिए, यह IEquatable लागू करने के लिए इतना है कि वस्तु आसानी से पहचान की है और चालाकी से किया जा सकता है एक अच्छा विचार है।


तुलना ऑपरेटर ==

डिफ़ॉल्ट रिटर्न से तुलना ऑपरेटर से सच है जब अपनी वस्तुओं के दोनों एक ही संदर्भ हैं।

यह is not recommended तुलना ऑपरेटर ओवरराइड करने के लिए जब तक आप with a value type काम कर रहे हैं (इस स्थिति में यह सिफारिश की है, Equals विधि के साथ) या अपरिवर्तनीय संदर्भ प्रकार है जो आप आमतौर पर मूल्य से तुलना होगा (जैसे string)। हमेशा एक ही समय में != लागू करें (वास्तव में मुझे requires a matching operator '!=' to also be defined त्रुटि मिलती है यदि मैं नहीं करता)।


संसाधन:

+2

बहुत बढ़िया जवाब:

यह नेट बेहतर में समानताओं को समझने के लिए एक उपयोगी कड़ी है। +1 – RPM1984

0

पुरातन के लिए, == ऑपरेटर के साथ चिपके रहते हैं।

.NET ढांचे में प्रदान की जाने वाली अधिकांश वस्तुओं और आपके द्वारा बनाई गई किसी भी कस्टम ऑब्जेक्ट्स में .quals() विधि और == ऑपरेटर केवल यह देखने के लिए जांच करेगा कि क्या दो ऑब्जेक्ट हीप पर उसी ऑब्जेक्ट को संदर्भित करते हैं या नहीं।

IEquatable इंटरफेस के उद्देश्य के संदर्भ समानता के लिए जाँच मूल्य समानता के लिए जाँच करने के लिए से अपने व्यवहार को बदलने के .Equals() विधि ओवरराइड करने के लिए है। सिस्टम। स्ट्रिंग प्रकार एक अंतर्निहित .NET ऑब्जेक्ट का एक उदाहरण है जो इस इंटरफ़ेस को लागू करता है।

.ReferenceEquals() विधि डेवलपर्स जो मानक .Equals ओवरराइड कर लिया है के लिए एक तरीका प्रदान करता() विधि अभी भी संदर्भित समानता के लिए दो वस्तुओं की जांच करने में सक्षम हो।

+2

"Primitives"? यह जावा नहीं है, मैंग! – Randolpho

1

समानता के प्रत्येक संस्करण थोड़ी अलग है। संदर्भ समानता के लिए

ReferenceEquals परीक्षण।

struct प्रकार के लिए वर्ग प्रकार के लिए संदर्भ समानता और मूल्य समानता के लिए डिफ़ॉल्ट चेक द्वारा virtual Equals। वांछित होने पर, समानता को अलग-अलग परिभाषित करने के लिए इसे ओवरराइड किया जा सकता है; और मूल्य प्रकारों के लिए ओवरराइड किया जाना चाहिए।

static Equals बस virtual Equals पर कॉल करता है, लेकिन null तर्कों के लिए भी अनुमति देता है।

IEquatable<T>.Equalsvirtual Equals के लिए एक सामान्य/प्रकार-सुरक्षित समकक्ष है।

operator== डिफ़ॉल्ट virtual Equals की तरह होना है, जिसका अर्थ वर्ग प्रकारों के लिए संदर्भ समानता है (जब तक कक्षा अन्य ऑपरेटरों को ओवरराइड नहीं करती)। इसे मूल्य प्रकारों के लिए भी ओवरराइड किया जाना चाहिए।

यदि आप अपनी खुद की संग्रह कक्षा लिखते हैं, तो IEqualityComparer<T> का उपयोग करें, EqualityComparer<T>.Default पर डिफ़ॉल्ट। किसी भी समानता तुलना का सीधे उपयोग न करें।

+0

thnx .. हमारे स्वयं के संग्रह वर्ग – Gaurav

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