none
为什么程序运行到Sort()方法这里,然后跳转到IComparable接口的实现方法中呢 RRS feed

  • 问题

  •     class Salary:IComparable
        {
            public string Name { get; set; }
            public int BaseSalary { get; set; }
    
    
    
    
            public int CompareTo(object obj)
            {
                Salary staff = obj as Salary;
                if (this.BaseSalary>staff.BaseSalary)
                {
                    return 1;
                }
                else if (this.BaseSalary == staff.BaseSalary)
                {
                    return 0;
                }
                else
                {
                    return -1;
                }
            }
        }

    进行排序

                ArrayList array = new ArrayList();
                array.Add(new Salary() { Name = "wang da", BaseSalary = 3600 });
                array.Add(new Salary() { Name = "xiao de zi", BaseSalary = 1800 });
                array.Add(new Salary() { Name = "li jing wen", BaseSalary = 7200 });
                array.Add(new Salary() { Name = "yang lin", BaseSalary = 2800 });
                array.Sort();
                foreach (Salary item in array)
                {
                    Console.WriteLine("{0} BaseSalary:{1}",item.Name,item.BaseSalary);
                }

    执行到 array.Sort(); 然后跳转到Salary类的CompareTo的方法中..这是为什么啊 .

    请大师解答下.小弟不胜感激.



    2017年9月1日 1:41

答案

  • wxp1188:

    默认情况下,对于List<T>的T系统根本不知道怎么进行比较(试想一下:给你一个未知类型的T,你怎么可能知道以什么作为标准进行比较呢?对吧?呵呵)。

    好了,问题来了,现在看微软怎么处理的(源代码):

     // Sorts the elements in this list.  Uses the default comparer and 
            // Array.Sort.
            public void Sort()
            {
                Sort(0, Count, null);
            }

    Sort又会调用一个重载函数:

    public void Sort(int index, int count, IComparer<T> comparer) {
                if (index < 0) {
                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                }
                
                if (count < 0) {
                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                }
                    
                if (_size - index < count)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
                Contract.EndContractBlock();
     
                Array.Sort<T>(_items, index, count, comparer);
                _version++;
            }

    最后看关键的Array的Sort:

     public static void Sort(Array array, int index, int length, IComparer comparer) {
                Sort(array, null, index, length, comparer);
            }
    调用内部重载Sort:
     public static void Sort(Array keys, Array items, int index, int length, IComparer comparer) {
                if (keys==null)
                    throw new ArgumentNullException("keys");
                if (keys.Rank != 1 || (items != null && items.Rank != 1))
                    throw new RankException(Environment.GetResourceString("Rank_MultiDimNotSupported"));
                if (items != null && keys.GetLowerBound(0) != items.GetLowerBound(0))
                    throw new ArgumentException(Environment.GetResourceString("Arg_LowerBoundsMustMatch"));
                if (index < keys.GetLowerBound(0) || length < 0)
                    throw new ArgumentOutOfRangeException((length<0 ? "length" : "index"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
                if (keys.Length - (index - keys.GetLowerBound(0)) < length || (items != null && (index - items.GetLowerBound(0)) > items.Length - length))
                    throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
     
                Contract.EndContractBlock();
                
                if (length > 1) {
                    if (comparer == Comparer.Default || comparer == null) {
                        bool r = TrySZSort(keys, items, index, index + length - 1);
                        if (r)
                            return;
                    }
     
                    Object[] objKeys = keys as Object[];
                    Object[] objItems = null;
                    if (objKeys != null)
                        objItems = items as Object[];
                    if (objKeys != null && (items==null || objItems != null)) {
                        SorterObjectArray sorter = new SorterObjectArray(objKeys, objItems, comparer);
                        sorter.Sort(index, length);
                    }
                    else {
                        SorterGenericArray sorter = new SorterGenericArray(keys, items, comparer);
                        sorter.Sort(index, length);
                    }
                }
            }

    注意SorterObjectArray中使用了IComparer,而当IComparer为空的时候,使用了实现的默认的DefaultComparer,然后看此代码:

     private struct SorterObjectArray
            {
                private Object[] keys;
                private Object[] items;
                private IComparer comparer;    
        
                internal SorterObjectArray(Object[] keys, Object[] items, IComparer comparer) {
                    if (comparer == null) comparer = Comparer.Default;
                    this.keys = keys;
                    this.items = items;
                    this.comparer = comparer;
                }
    ……
    }

    那么Default的Comparer实现呢?

     public int Compare(Object a, Object b) {
                if (a == b) return 0;
                if (a == null) return -1;
                if (b == null) return 1;
                if (m_compareInfo != null) {
                    String sa = a as String;
                    String sb = b as String;
                    if (sa != null && sb != null)
                        return m_compareInfo.Compare(sa, sb);
                }
     
                IComparable ia = a as IComparable;
                if (ia != null)
                    return ia.CompareTo(b);
     
                IComparable ib = b as IComparable;
                if (ib != null)
                    return -ib.CompareTo(a);
    ……
    }

    Reproduce your quesions with ScreenToGif is your choice.
    For IIS: IIS Forum,
    For WebSite of .NET: ASP.NET Forum,
    For others: StackExchange.
    For spam-sender or forum urgent issues, Send your Email at:  forumsfeedback@microsoft.com

    • 已标记为答案 wxp1188 2017年9月2日 19:03
    2017年9月1日 10:46
    版主

全部回复

  • Hi wxp1188,

    感谢你在MSDN论坛发帖。

    如果你看了这个sort方法的简介,你就会发现为什么会调用到compareTo这个方法。

    Each element of array must implement the IComparable interface to be capable of comparisons with every other element in array.

    通过这句话,我想你应该知道原因了吧, 数组里面每一个元素都必须实现这个IComparable 这个接口。

    希望我的回复能对你有所帮助,如果你的问题解决了,请及时标记有用的回复作为答案,这样会帮助遇到相同问题的人。

    更详细的信息,你可以参考这个文档。

    Best Regards,

    Hart


    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2017年9月1日 8:28
    版主
  • wxp1188:

    默认情况下,对于List<T>的T系统根本不知道怎么进行比较(试想一下:给你一个未知类型的T,你怎么可能知道以什么作为标准进行比较呢?对吧?呵呵)。

    好了,问题来了,现在看微软怎么处理的(源代码):

     // Sorts the elements in this list.  Uses the default comparer and 
            // Array.Sort.
            public void Sort()
            {
                Sort(0, Count, null);
            }

    Sort又会调用一个重载函数:

    public void Sort(int index, int count, IComparer<T> comparer) {
                if (index < 0) {
                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                }
                
                if (count < 0) {
                    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
                }
                    
                if (_size - index < count)
                    ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_InvalidOffLen);
                Contract.EndContractBlock();
     
                Array.Sort<T>(_items, index, count, comparer);
                _version++;
            }

    最后看关键的Array的Sort:

     public static void Sort(Array array, int index, int length, IComparer comparer) {
                Sort(array, null, index, length, comparer);
            }
    调用内部重载Sort:
     public static void Sort(Array keys, Array items, int index, int length, IComparer comparer) {
                if (keys==null)
                    throw new ArgumentNullException("keys");
                if (keys.Rank != 1 || (items != null && items.Rank != 1))
                    throw new RankException(Environment.GetResourceString("Rank_MultiDimNotSupported"));
                if (items != null && keys.GetLowerBound(0) != items.GetLowerBound(0))
                    throw new ArgumentException(Environment.GetResourceString("Arg_LowerBoundsMustMatch"));
                if (index < keys.GetLowerBound(0) || length < 0)
                    throw new ArgumentOutOfRangeException((length<0 ? "length" : "index"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
                if (keys.Length - (index - keys.GetLowerBound(0)) < length || (items != null && (index - items.GetLowerBound(0)) > items.Length - length))
                    throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
     
                Contract.EndContractBlock();
                
                if (length > 1) {
                    if (comparer == Comparer.Default || comparer == null) {
                        bool r = TrySZSort(keys, items, index, index + length - 1);
                        if (r)
                            return;
                    }
     
                    Object[] objKeys = keys as Object[];
                    Object[] objItems = null;
                    if (objKeys != null)
                        objItems = items as Object[];
                    if (objKeys != null && (items==null || objItems != null)) {
                        SorterObjectArray sorter = new SorterObjectArray(objKeys, objItems, comparer);
                        sorter.Sort(index, length);
                    }
                    else {
                        SorterGenericArray sorter = new SorterGenericArray(keys, items, comparer);
                        sorter.Sort(index, length);
                    }
                }
            }

    注意SorterObjectArray中使用了IComparer,而当IComparer为空的时候,使用了实现的默认的DefaultComparer,然后看此代码:

     private struct SorterObjectArray
            {
                private Object[] keys;
                private Object[] items;
                private IComparer comparer;    
        
                internal SorterObjectArray(Object[] keys, Object[] items, IComparer comparer) {
                    if (comparer == null) comparer = Comparer.Default;
                    this.keys = keys;
                    this.items = items;
                    this.comparer = comparer;
                }
    ……
    }

    那么Default的Comparer实现呢?

     public int Compare(Object a, Object b) {
                if (a == b) return 0;
                if (a == null) return -1;
                if (b == null) return 1;
                if (m_compareInfo != null) {
                    String sa = a as String;
                    String sb = b as String;
                    if (sa != null && sb != null)
                        return m_compareInfo.Compare(sa, sb);
                }
     
                IComparable ia = a as IComparable;
                if (ia != null)
                    return ia.CompareTo(b);
     
                IComparable ib = b as IComparable;
                if (ib != null)
                    return -ib.CompareTo(a);
    ……
    }

    Reproduce your quesions with ScreenToGif is your choice.
    For IIS: IIS Forum,
    For WebSite of .NET: ASP.NET Forum,
    For others: StackExchange.
    For spam-sender or forum urgent issues, Send your Email at:  forumsfeedback@microsoft.com

    • 已标记为答案 wxp1188 2017年9月2日 19:03
    2017年9月1日 10:46
    版主
  • 感谢 ,这样就符合逻辑了 /
    2017年9月2日 16:48