2011-05-31 8 views
6

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

using System; 
using System.Collections.Generic; 

namespace SortingNulls 
{ 
    internal class Child : IComparable<Child> 
    { 
    public int Age; 
    public string Name; 

    public int CompareTo(Child other) 
    { 
     if (other == null) 
     return -1; // what's your problem? 

     return this.Age.CompareTo(other.Age); 
    } 

    public override string ToString() 
    { 
     return string.Format("{0} ({1} years)", this.Name, this.Age); 
    } 
    } 

    internal static class Program 
    { 
    private static void Main() 
    { 
     var listOfChilds = new List<Child> 
     { 
     null, 
     null, 
     null, 
     null, 
     new Child { Age = 5, Name = "Joe" }, 
     new Child { Age = 6, Name = "Sam" }, 
     new Child { Age = 3, Name = "Jude" }, 
     new Child { Age = 7, Name = "Mary" }, 
     null, 
     null, 
     null, 
     null, 
     new Child { Age = 7, Name = "Pete" }, 
     null, 
     new Child { Age = 3, Name = "Bob" }, 
     new Child { Age = 4, Name = "Tim" }, 
     null, 
     null, 
     }; 

     listOfChilds.Sort(); 

     Console.WriteLine("Sorted list begins here"); 
     for (int i = 0; i < listOfChilds.Count; ++i) 
     Console.WriteLine("{0,2}: {1}", i, listOfChilds[i]); 
     Console.WriteLine("Sorted list ends here"); 
    } 
    } 
} 

ऊपर कोड चल रहा है, आप देखते हैं कि अशक्त संदर्भ के रूप में उम्मीद पृथक नहीं किया जा। जाहिर है, ए से बी की तुलना करते समय, यदि ए ऑब्जेक्ट है और बी शून्य है, तो उपयोगकर्ता द्वारा परिभाषित तुलना का उपयोग किया जाता है, लेकिन यदि विपरीत रूप से ए शून्य है और बी एक ऑब्जेक्ट है, तो इसके बजाय कुछ बीसीएल तुलना का उपयोग किया जाता है।

क्या यह एक बग है?

उत्तर

8

नहीं, यह एक बग नहीं है। आपकी CompareTo विधि जो IComparable<Child> लागू करती है, को आपके Child कक्षा पर परिभाषित किया गया है। दूसरे शब्दों में, यदि आपको तुलना करने के लिए आपको अपने किसी एक प्रकार पर एक विधि का आह्वान करना है।

यदि Child की तुलना की जा रही वस्तुओं में से एक शून्य है, तो आप CompareTo पर कैसे आ सकते हैं?

ध्यान दें कि IComparable की परिभाषा से:

"परिभाषा के अनुसार, किसी भी वस्तु से अधिक तुलना (या इस प्रकार है) एक अशक्त संदर्भ (विजुअल बेसिक में कुछ नहीं), और दो अशक्त संदर्भ एक दूसरे के बराबर की तुलना करें। "

जो आपके द्वारा देखे जाने वाले परिणामों को बताता है।

समाधान तुलना करने के लिए किसी अन्य वर्ग को सौंपना है। IComparer इंटरफ़ेस देखें।

+0

अच्छा जवाब। मैंने यह नहीं देखा था कि प्रलेखन ने कहा था कि किसी ऑब्जेक्ट को शून्य से अधिक की तुलना करनी चाहिए। जब ए शून्य है और बी शून्य नहीं है, तो फ्रेमवर्क * ए और बी को बदल सकता है, जिसे मेरी विधि कहा जाता है, और फिर लौटाए गए इंट 32 के संकेत को फ़्लिप कर दिया। मुझे लगता है कि कभी-कभी पुराने नोंगनेरिक आईसीओपरपेबल के साथ होता है। निश्चित रूप से एक आईसीओएमपेयर या एक तुलना प्रतिनिधि के साथ पहले पैरामीटर के रूप में शून्य को संभालना आसान है। – JeppeSN

1

this.Age.CompareTo(other.Age); का मूल्यांकन करने का प्रयास करने पर आपको क्या उम्मीद होगी यदि thisnull है? वास्तव में, this सी # में कभी भी null नहीं हो सकता है।

यह पूछने के लिए कि यह एक बग है, this blog post देखें।

1

डिफ़ॉल्ट Comparer<T> एक प्रकार T के लिए परिदृश्य को ध्यान में रखना है जहां पहला तत्व (चलो इसे ए कॉल करें) null है। मान लें कि यह कुछ इस तरह दिखता है:

if (ReferenceEquals(a, null)) 
{ 
    return -1; 
} 

return a.CompareTo(b); 

यह the documentation of List<T>.Sort पर आधारित है:

इस विधि करने के लिए डिफ़ॉल्ट comparer Comparer(Of T).Default प्रकार टी के लिए उपयोग करता सूची तत्वों का क्रम निर्धारण करते हैं।

बेशक, शीर्ष कदम केवल लौट सकते हैं 0अगर दोनों तत्वों null हैं, और अन्यथा b.CompareTo(a) के विपरीत का उपयोग करें।

मैं वास्तव में इसे बग कहूंगा नहीं। यह सिर्फ कुछ पता होना चाहिए।

1

नहीं है, अपने अपने कोड अपने मानकों कि IComparable.CompareTo() परिभाषित का पालन नहीं कर के रूप में है कि एक "बग" है: IComparable

विशेष रूप

: परिभाषा के अनुसार, किसी भी वस्तु से अधिक तुलना (या इस प्रकार) null, और दो null संदर्भ एक दूसरे के बराबर तुलना करते हैं।

अपने उदाहरण में आप null से छोटे (या पूर्ववर्ती) की तुलना करने के लिए अपनी वस्तु को परिभाषित कर रहे हैं, जो ठीक से किया जाना चाहिए इसके विपरीत है।