2013-11-15 9 views
10

मैं structs के संग्रह पर FirstOrDefault() का उपयोग करने के बाद कुछ अजीब व्यवहार देख रहा हूं। मैंने इसे इस प्रजनन मामले में अलग कर दिया है। इस कार्यक्रम केऑपरेटर '==' को संरचना और डिफ़ॉल्ट (संरचना) पर क्यों लागू नहीं किया जा सकता है?

using System; 
using System.Linq; 

namespace MyProgram { 
    public class Program { 
     static void Main() { 

      var users = new User[] { 
      new User() { UserGuid = Guid.NewGuid(), Username = "user01" }, 
      new User() { UserGuid = Guid.NewGuid(), Username = "user02" } 
     }; 

      var user = users.FirstOrDefault(u => u.Username == "user01"); 
      Console.WriteLine(user == default(User) ? "not found" : "found"); 
     } 

    } 

    public struct User { 
     public Guid UserGuid; 
     public string Username; 
    } 
} 

संकलन नहीं होगा संकलक त्रुटि बल्कि गुप्त है:

ऑपरेटर '==' प्रकार 'MyProgram.User' और 'MyProgram.User' की ऑपरेंड के लिए लागू नहीं किया जा सकता

कक्षा में संरचना को बदलना ठीक काम करता है - लेकिन मुझे नुकसान है कि मैं एक संरचना 'आवृत्ति' की तुलना डिफ़ॉल्ट रूप से क्यों नहीं कर सकता?

+1

क्योंकि कक्षाओं के लिए यह सूचक तुलना करेगा। संरचना के लिए इसे परिभाषित नहीं किया गया है (क्योंकि इसे एक विस्तृत प्रतिबिंब तुलना करना चाहिए जब तक कि इसे कार्यान्वयनकर्ता द्वारा परिभाषित नहीं किया गया हो)। सोचें कि संरचना में कक्षाएं हैं (यह संभव है)। उस मामले में तुलना कैसे की जानी चाहिए (केवल संदर्भ द्वारा? प्रत्येक वर्ग के लिए कॉलिंग तुलना ऑपरेटर?)। इसके अलावा सोचें कि संरचना में बड़े डेटा सरणी हैं (खराब बुरी प्रथा है लेकिन इसकी अनुमति है और आपकी उत्तरदायित्व के तहत)। इसके लिए किस कंपाइलर को उत्सर्जित करना चाहिए? इसी कारण से ** आईएमओ भी बराबर कॉल() बहुत सुंदर अक्षम है **। –

+1

संभावित डुप्लिकेट [==] का उपयोग करके दो structs की तुलना करना (http://stackoverflow.com/questions/15199026/comparing-two-structs-using) – Stijn

+0

किसी भी वर्ग के बजाय आप किसी स्ट्रक्चर का उपयोग क्यों कर रहे हैं? (मैं आपके फैसले पर सवाल नहीं उठा रहा हूं, बस सोच रहा हूं कि आपने इसके बारे में सोचा है और मतभेदों को समझ लिया है।) –

उत्तर

13

कक्षाओं के लिए, == ऑपरेटर संदर्भ समानता का उपयोग करता है। बेशक, structs मूल्य प्रकार हैं, इसलिए संदर्भ से तुलना नहीं की जा सकती है। Structs के लिए == का कोई डिफ़ॉल्ट कार्यान्वयन नहीं है क्योंकि सदस्य के अनुसार तुलना हमेशा तुलनात्मक रूप से वैध तुलना नहीं होती है। Object.Equals कॉल करने के लिए

Console.WriteLine(user.Equals(default(User)) ? "not found" : "found"); 

या फिर आप == को लागू कर सकते हैं::

इसके बजाय आप Object.Equals विधि है, जो सदस्य वार तुलना करता है का उपयोग कर सकते

public static bool operator ==(User lhs, User rhs) 
{ 
    return lhs.Equals(rhs); 
} 

हालांकि, structs के लिए Equals के डिफ़ॉल्ट कार्यान्वयन प्रतिबिंब का उपयोग करता है, और इसलिए बहुत धीमा है। बेहतर होगा कि Equals खुद को लागू करने, == और != के साथ (और संभवतः GetHashCode भी):

public override bool Equals(Object obj) 
{ 
    return obj is User && Equals((User)obj); 
} 

public bool Equals(User other) 
{ 
    return UserGuid == other.UserGuid && Username == other.Username; 
} 

public static bool operator ==(User lhs, User rhs) 
{ 
    return lhs.Equals(rhs); 
} 

public static bool operator !=(User lhs, User rhs) 
{ 
    return !lhs.Equals(rhs); 
} 
+0

बस जो आपने कहा है उसे जोड़ने के लिए, यदि आप 'बराबर' ओवरराइड करते हैं, तो आपको एक कंपाइलर चेतावनी मिलती है कि आपको 'GetHashCode' को ओवरराइड करना चाहिए। –

+0

लेकिन int एक वैल्यू प्रकार भी है और हम अभी भी दो इंट्स की तुलना करने के लिए == का उपयोग करते हैं। – rajibdotnet

0

आप == ऑपरेटर को ओवरलोड कर सकते हैं यदि आप इस

public static bool operator ==(User u1, User u2) 
    { 
     return u1.Equals(u2) 
    } 

अगर आपको == ओवरराइड Equals और GetHashCode()

इसके अलावा ओवरराइड करना चाहिए क्या करना चाहते हैं, तो आप शायद के रूप में != ओवरराइड करना चाहते जाएगा कुंआ।

public static bool operator !=(User u1, User u2) 
    { 
     return !u1.Equals(u2) 
    } 
2

तुम बस इसे लागू करने के लिए है:

public static bool operator == (User u1, User u2) 
{ 
    return u1.Equals(u2); // use ValueType.Equals() which compares field-by-field. 
} 
+0

आपको '! =' को भी लागू करना होगा। Https://stackoverflow.com/a/15199135/695964 – KFL

0

जब आप दो संदर्भ प्रकार की तुलना, आप जाँच कर रहे हैं संदर्भ में एक ही प्रकार को इंगित करता है।

लेकिन यदि आप मूल्य प्रकारों से निपट रहे हैं, तो तुलना करने के लिए कोई संदर्भ नहीं हैं।

आपको ऑपरेटर को स्वयं लागू करना होगा, और (संभवतः) जांच करें कि मान प्रकार के फ़ील्ड मेल खाते हैं या नहीं।

1

सी # में, == टोकन दो अलग-अलग ऑपरेटरों (नहीं सभी भाषाओं के लिए एक ही टोकन का उपयोग प्रतिनिधित्व करने के लिए प्रयोग किया जाता है दो ऑपरेटरों; वीबीएनईटी टोकन = और Is का उपयोग करता है)।ऑपरेटरों में से एक अधिभार योग्य समानता परीक्षण है, और केवल उन मामलों में प्रयोग योग्य है जहां या तो ओवरलोड को दोनों ऑपरेटरों प्रकारों के लिए परिभाषित किया जाता है, या एक ओवरलोड को एक ऑपरेंड प्रकार के लिए परिभाषित किया जाता है और एक प्रकार जिस पर अन्य ऑपरेंड निहित रूप से परिवर्तनीय होता है। दूसरा ऑपरेटर एक संदर्भ-समानता परीक्षण का प्रतिनिधित्व करता है, और उन मामलों में प्रयोग योग्य है जहां समानता परीक्षण ऑपरेटर अनुपयोगी होगा, और जहां एक ऑपरेंड एक वर्ग प्रकार है जो दूसरे से प्राप्त होता है, एक ऑपरेंड एक वर्ग प्रकार होता है और दूसरा एक होता है इंटरफेस प्रकार, या दोनों ऑपरेटरों इंटरफ़ेस प्रकार हैं।

पहला समानता-परीक्षण ऑपरेटर किसी भी प्रकार (वर्ग, इंटरफ़ेस या संरचना) के साथ उपयोग नहीं किया जा सकता है जो इसके लिए एक स्पष्ट ओवरराइड प्रदान नहीं करता है। यदि == टोकन उन मामलों में उपयोग किया जाता है जहां पहला समानता-परीक्षण ऑपरेटर उपयोग योग्य नहीं है, हालांकि, सी # दूसरे ऑपरेटर का उपयोग करने का प्रयास करेगा [ध्यान दें कि वीबी.नेट जैसी अन्य भाषाएं ऐसा नहीं करतीं; VB.NET में, = का उपयोग करने की कोशिश करने के लिए एक समानता-परीक्षण ओवरलोड को परिभाषित नहीं करने वाली दो चीजों की तुलना करने के लिए एक त्रुटि होगी, भले ही चीजों की तुलना Is ऑपरेटर का उपयोग करके की जा सके। उस दूसरे ऑपरेटर का उपयोग किसी संदर्भ प्रकार की तुलना उसी प्रकार के किसी अन्य संदर्भ से करने के लिए किया जा सकता है, लेकिन संरचनाओं के साथ प्रयोग योग्य नहीं है। चूंकि संरचनाओं के लिए समानता के समानता ऑपरेटर को परिभाषित नहीं किया गया है, इसलिए तुलना की अनुमति नहीं है।

यदि एक सोच है क्यों == बस Equals(Object) है, जो सभी प्रकार के साथ प्रयोग करने योग्य है पर वापस नहीं आता, कारण यह है कि == के दोनों ऑपरेंड तरीके कि Equals मिलान से अपने व्यवहार रोकेगा बलात्कार टाइप करने के लिए अधीन हैं। उदाहरण के लिए, 1.0 एफ == 1.0, और 1.0 == 1.0 एफ, दोनों ने float ऑपरेशन double पर डाला, लेकिन (1.0f).Equals(1.0) जैसे अभिव्यक्ति को दिया गया पहला ऑपरेंड का मूल्यांकन float पर कुछ भी नहीं किया जा सकता है। इसके अलावा, यदि == को Equals पर मैप किया गया था, तो संदर्भ # समानता परीक्षण का प्रतिनिधित्व करने के लिए सी # के लिए एक अलग टोकन का उपयोग करना आवश्यक था [कुछ भी भाषा को वैसे भी करना चाहिए था, लेकिन स्पष्ट रूप से ऐसा नहीं करना चाहता था]।

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