2017-07-07 5 views
15

मैं कोड के इस नमूने और OpTest को आजमा रहा हूं जब System.Console.WriteLine(s == t); यह false देता है। क्या कोई इसे समझा सकता है?स्ट्रिंगबिल्डर और स्ट्रिंग समानता जांच

public static void OpTest<T>(T s, T t) where T : class 
{ 
    System.Console.WriteLine(s == t); 
} 
static void Main() 
{ 
    string s1 = "строка"; 
    System.Text.StringBuilder sb = new System.Text.StringBuilder(s1); 
    System.Console.Write(sb); 
    string s2 = sb.ToString(); 
    OpTest<string>(s1, s2); 
} 
+0

यह आईएल को देखने में मदद करता है उदा। इस प्रकार के व्यवहार को स्वयं शोधने के लिए ildasm का उपयोग करना। – Jeroen

+0

यदि आप जेनेरिक कोड उपयोग में समानता के लिए तुलना करना चाहते हैं तो 'समानता कॉम्पैयर .default.Equals (एस, टी)' और वैकल्पिक रूप से उपयोगकर्ता को अपने 'IEqualityComparer ' पास करने की अनुमति देता है। – CodesInChaos

+0

== और बराबर() के बीच [सी # अंतर का संभावित डुप्लिकेट (https://stackoverflow.com/questions/814878/c-sharp-difference-between-and-equals) – Dukeling

उत्तर

16

आपका सामान्य विधि मूल रूप से एक संदर्भ समानता की जांच प्रदर्शन किया जाएगा - और s1 के मूल्यों और s2 अलग लेकिन समान तार को देखें। आप इस तरह के और अधिक आसानी से इस दिखा सकते हैं:

string x = "test"; 
string y = new string(x.ToCharArray()); 
Console.WriteLine(x == y); // Use string overload, checks for equality, result = true 
Console.WriteLine(x.Equals(y)); // Use overridden Equals method, result = true 
Console.WriteLine(ReferenceEquals(x, y)); // False because they're different objects 
Console.WriteLine((object) x == (object) y); // Reference comparison again - result = false 

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

यदि आपने T को किसी प्रकार से प्राप्त करने के लिए बाध्य किया है जो == ऑपरेटर को अधिभारित करता है, तो संकलक उस अधिभार का उपयोग करेगा। उदाहरण के लिए:

using System; 

class SillyClass 
{ 
    public static string operator ==(SillyClass x, SillyClass y) => "equal"; 
    public static string operator !=(SillyClass x, SillyClass y) => "not equal"; 
} 

class SillySubclass : SillyClass 
{ 
    public static string operator ==(SillySubclass x, SillySubclass y) => "sillier"; 
    public static string operator !=(SillySubclass x, SillySubclass y) => "very silly"; 
} 

class Test 
{ 
    static void Main() 
    { 
     var x = new SillySubclass(); 
     var y = new SillySubclass(); 
     OpTest(x, y); 
    } 

    static void OpTest<T>(T x, T y) where T : SillyClass 
    { 
     Console.WriteLine(x == y); 
     Console.WriteLine(x != y); 
    } 
} 

यहाँ OpTest विधि है अतिभारित ऑपरेटर का उपयोग - लेकिन केवल कभी SillyClass, नहीं SillySubclass से लोगों को।

2

s == tOpTest<T> संदर्भ समानता के लिए विधि जांच, मूल्य समानता नहीं है। इस मामले में, यह StringBuilder कक्षा दोनों के संदर्भ स्रोत के अंतर के कारण false देता है।

true मूल्य पाने के लिए आपको Equals विधि का उपयोग करने की जरूरत है:

public static void OpTest<T>(T s, T t) where T : class 
{ 
    System.Console.WriteLine(s.Equals(t)); 
} 

डेमो: .NET Fiddle Example

+0

साइड नोट: यदि 's' है शून्य: 'string.Equals (एस, टी)'। – JohnLBevan

2

यह इसलिए होता है क्योंकि आप एक सामान्य विधि का उपयोग कर रहे हैं और आप विशेष रूप से class के प्रकार के लिए सामान्य पैरामीटर प्रतिबंधित ।

डिफ़ॉल्ट रूप से, सामान्य प्रकारों में समानता ऑपरेटर == परिभाषित नहीं होता है।

कक्षा में <T> के संभावित प्रकारों को प्रतिबंधित करने से s == t संभव हो जाता है। हालांकि, अब यह class प्रतिबंध द्वारा निर्दिष्ट डिफ़ॉल्ट कार्यान्वयन का उपयोग करेगा और यह संदर्भ समानता का उपयोग कर रहा है।

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

यदि आप दोनों मामलों में एक ही स्ट्रिंग अक्षर का उपयोग करते हैं, तो यह true लौटाएगा क्योंकि शाब्दिक केवल एक बार उत्पन्न होता है और फिर इसे हर बार संदर्भित किया जाएगा।

4

पहले से ही कई उत्तर हैं, लेकिन मेरे पास जोड़ने के लिए कुछ अतिरिक्त है। यदि आप इस तरह के मुद्दे पर फंस गए हैं तो यह उत्पन्न आईएल देखने के लिए ildasm.exe का उपयोग करने में मदद कर सकता है।उदाहरण के लिए:

public class Foo 
{ 
    public static void OpTest_1<T>(T s, T t) where T : class 
    { 
     var val = s == t; 
    } 

    public static void OpTest_2(string s, string t) 
    { 
     var val = s == t; 
    } 

    // Does not compile. 
    //public static void OpTest_3<T>(T s, T t) where T : struct 
    //{ 
    // var val = s == t; 
    //} 
} 

OpTest_1 के लिए देता है:

.method public hidebysig static void OpTest_1<class T>(!!T s, !!T t) cil managed 
{ 
    // Code size  17 (0x11) 
    .maxstack 2 
    .locals init ([0] bool val) 
    IL_0000: nop 
    IL_0001: ldarg.0 
    IL_0002: box  !!T 
    IL_0007: ldarg.1 
    IL_0008: box  !!T 
    IL_000d: ceq 
    IL_000f: stloc.0 
    IL_0010: ret 
} // end of method Foo::OpTest_1 

तो आप इसे कॉल ceq जो संदर्भ समानता के लिए जाँच करता है देखते हैं।

.method public hidebysig static void OpTest_2(string s, string t) cil managed 
{ 
    // Code size  10 (0xa) 
    .maxstack 2 
    .locals init ([0] bool val) 
    IL_0000: nop 
    IL_0001: ldarg.0 
    IL_0002: ldarg.1 
    IL_0003: call  bool [mscorlib]System.String::op_Equality(string, string) 
    IL_0008: stloc.0 
    IL_0009: ret 
} // end of method Foo::OpTest_2 

कि ceq लेकिन mscorlib में स्ट्रिंग समानता आपरेशन का उपयोग नहीं करता है और उम्मीद के रूप में एक परिणाम दे देंगे:

एक दूसरे इस आईएल है।

जैसा मैंने कहा, बस इस मुद्दे पर शोध करने का एक और तरीका जोड़ने के लिए। अधिक उच्च स्तर के विवरण के लिए मैं @JonSkeet's answer पढ़ने की सिफारिश करता हूं।

+0

"तो आप देखते हैं कि यह दोनों तारों को बॉक्स करता है" - वास्तव में नहीं। यहां 'बॉक्स' निर्देश बाधा के कारण कुछ हद तक व्यर्थ है ... यह केवल तभी होगा जब टाइप तर्क एक मान प्रकार है, जो यह यहां नहीं है। –

+0

@ जोन्सस्केट सुधार के लिए धन्यवाद, सीखने के रूप में मैं यहां जाता हूं: डी। मैंने स्पष्ट रूप से उस टिप्पणी को हटा दिया है, उम्मीद है कि मेरा जवाब सही कर देगा। (यह सुनिश्चित नहीं था कि मेरे उत्तर में आपकी टिप्पणी के दूसरे भाग को कैसे शामिल किया जाए, लेकिन यदि आप देखते हैं कि यह उत्तर में कैसे जोड़ता है और सोचता है तो इसे संपादित करने में संकोच न करें।) – Jeroen

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