2010-12-14 16 views
8

मेरे पास एक वर्ग है जिसमें इसमें कुछ स्ट्रिंग सदस्य, कुछ डबल सदस्य और कुछ सरणी वस्तुएं हैं।वस्तुओं की तुलना

मैं इस वर्ग के दो वस्तुओं को बनाने, वहाँ किसी भी सरल, इन वस्तुओं की तुलना और उनके बराबर का कहना है की कारगर तरीका है? कोई सुझाव?

मुझे पता है कि तुलनात्मक कार्य कैसे लिखना है, लेकिन यह समय लेने वाला होगा।

+2

वस्तुओं के बराबर होने के लिए आपकी क्या शर्तें हैं? – BoltClock

+0

मूल रूप से, इन स्ट्रिंग सदस्यों, डबल सदस्यों और सरणी में सभी मान समान होना चाहिए! – siva

+1

http://stackoverflow.com/questions/506096/comparing-object-properties-in-c – RameshVel

उत्तर

11

एक ही रास्ता तुम सच में ऐसा कर सकते हैं bool Object.Equals(object other) ओवरराइड सच वापस जाने के लिए जब समानता आपकी शर्तों को पूरा कर रहे हैं, और नहीं तो झूठी वापस जाने के लिए है। तुम भी int Object.GetHashCode() ओवरराइड किसी पूर्णांक डेटा है कि आप मानते हैं Equals() अधिभावी के सभी से गणना की वापस जाने के लिए आवश्यक है।

एक तरफ के रूप में, ध्यान दें कि GetHashCode() के लिए अनुबंध निर्दिष्ट करता है कि वापसी मूल्य दो वस्तुओं के बराबर होना चाहिए जब Equals() उनकी तुलना करते समय सत्य वापस आ जाएगा। इसका मतलब है कि return 0;GetHashCode() का एक मान्य कार्यान्वयन है लेकिन यह अक्षमताओं के कारण होगा जब अपने वर्ग की वस्तुओं, एक HashSet<T> में संग्रहीत शब्दकोश कुंजी के रूप में उपयोग किया जाता है या।

तरह से मैं समानता लागू इस तरह है:

public class Foo : IEquatable<Foo> 
{ 
    public bool Equals(Foo other) 
    { 
     if (other == null) 
      return false; 

     if (other == this) 
      return true; // Same object reference. 

     // Compare this to other and return true/false as appropriate. 
    } 

    public override bool Equals(Object other) 
    { 
     return Equals(other as Foo); 
    } 

    public override int GetHashCode() 
    { 
     // Compute and return hash code. 
    } 
} 

GetHashCode() को लागू करने का एक आसान तरीका एक साथ डेटा आप Equals() में समानता के लिए विचार के सभी के हैश कोड XOR है। तो अगर, उदाहरण के लिए, गुण आप समानता के लिए तुलना string FirstName; string LastName; int Id; कर रहे हैं, अपने कार्यान्वयन लग सकता है जैसे:

public override int GetHashCode() 
{ 
    return (FirstName != null ? FirstName.GetHashCode() : 0)^
     (LastName != null ? LastName.GetHashCode() : 0)^
     Id; // Primitives of <= 4 bytes are their own hash codes 
} 

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

1

सर्वश्रेष्ठ उत्तर अपनी कक्षा के लिए IEquatable लागू करने के लिए है - यह जवाब आप सुनना चाहते नहीं हो सकता है, लेकिन जो .NET में मूल्य तुल्यता लागू करने के लिए सबसे अच्छा तरीका है।

एक अन्य विकल्प अपने वर्ग के सदस्यों के सभी की एक अद्वितीय हैश कंप्यूटिंग और फिर उन के खिलाफ मूल्य की तुलना करते समय होगा, लेकिन है कि एक तुलना समारोह लिखने की तुलना में और भी अधिक काम है, 'उचित' के लिए रास्ता)

+0

हैश दृष्टिकोण झूठी सकारात्मक भी है। – cdhowie

+0

हाँ, वास्तव में इसकी अनुशंसा नहीं करते हैं। – Aaronontheweb

9

यदि आप वास्तव में यह सही करने के लिए, this isn't all you should do चाहते हैं,

public class SomeClass : IEquatable<SomeClass> 
{ 
    public string Name { get; set; } 
    public double Value { get; set; } 
    public int[] NumberList { get; set; } 

    public bool Equals(SomeClass other) 
    { 
     // whatever your custom equality logic is 
     return other.Name == Name && 
      other.Value == Value && 
      other.NumberList == NumberList; 
    } 
} 

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

public class SomeClass : IEquatable<SomeClass> 
{ 
    public string Name { get; set; } 
    public double Value { get; set; } 
    public int[] NumberList { get; set; } 

    /// <summary> 
    /// Explicitly implemented IEquatable method. 
    /// </summary> 
    public bool IEquatable<SomeClass>.Equals(SomeClass other) 
    { 
     return other.Name == Name && 
      other.Value == Value && 
      other.NumberList == NumberList; 
    } 

    public override bool Equals(object obj) 
    { 
     var other = obj as SomeClass; 
     if (other == null) 
      return false; 
     return ((IEquatable<SomeClass>)(this)).Equals(other); 
    } 

    public override int GetHashCode() 
    { 
     // Determine some consistent way of generating a hash code, such as... 
     return Name.GetHashCode()^Value.GetHashCode()^NumberList.GetHashCode(); 
    } 
} 
1

चूंकि ये वस्तुएं हैं मेरा अनुमान यह है कि आपको वस्तुओं के लिए समान विधि को ओवरराइड करना होगा। अन्यथा बराबर विधि आपको केवल तभी ठीक करेगी जब दोनों वस्तुएं एक ही वस्तु को प्रतिबिंबित करती हैं।

मुझे पता है कि यह वह जवाब नहीं है जिसे आप चाहते हैं। लेकिन चूंकि आपकी कक्षा में बहुत कम संपत्तियां हैं, इसलिए आप आसानी से विधि को ओवरराइड कर सकते हैं।

5

बस पूरे दिन एक अलग-अलग संपत्ति प्रकार से निपटने के लिए तर्क के विभिन्न जटिल बिट्स के साथ किसी ऑब्जेक्ट के गुणों को प्रतिबिंबित करके एक विस्तार विधि लूपिंग लिखने और वास्तव में इसे अच्छे के करीब ले गया, फिर 16:55 पर यह मेरे सामने आया कि अगर आप दो वस्तु को क्रमानुसार, तो आप बस दो तार की तुलना

जरूरत है ... ओह तो यहाँ एक सरल serializer विस्तार विधि है कि यहां तक ​​कि शब्दकोश

public static class TExtensions 
    { 
     public static string Serialize<T>(this T thisT) 
     { 
      var serializer = new DataContractSerializer(thisT.GetType()); 
      using (var writer = new StringWriter()) 
      using (var stm = new XmlTextWriter(writer)) 
      { 
       serializer.WriteObject(stm, thisT); 
       return writer.ToString(); 
      } 
     } 
} 

पर काम करता है अब आप अपने परीक्षण के रूप में सरल किया जा सकता है

Asset.AreEqual(objA.Serialise(), objB.Serialise()) 

अभी तक व्यापक परीक्षण नहीं किया है, लेकिन यह आशाजनक और अधिक महत्वपूर्ण बात सरल है। किसी भी तरह से अभी भी आपके उपयोगिता सेट में एक उपयोगी तरीका है?

+0

लेकिन यदि आपके ऑब्जेक्ट में स्ट्रिंग गुण होते हैं, तो ऊपरी/निचले मामले तुलनात्मक नहीं होंगे? मेरा मतलब है, 'यूनाइटेडस्टेट्स' 'संयुक्त स्टेटस' के लिए असमान होगा। –

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