繁体   English   中英

无法在Array.BinarySearch中调用键的比较器

[英]Can't invoke the comparator of the key in Array.BinarySearch

为了观察System.Array.BinarySearch中键的比较器的调用(与涉及调用数组元素的比较器的典型方案相反),我们设置了以下测试:

class Many 
{
    public string data { get; set; }
}
class One : Many, IComparable
{
    public int CompareTo(object arg)
    {
        Many other = arg as Many;
        Console.WriteLine("Comparator of One invoked from: " + this.data);
        if (this.data.Length < other.data.Length) return -1;
        if (this.data.Length > other.data.Length) return 1;
        return 0;
    }
}

使用这些新的声明时,我运行以下命令:

   Many[] manies = new[] { new Many { data = "1" }, 
                           new Many { data = "22" }, 
                           new Many { data = "333" }, 
                           new Many { data = "4444" }, };
   One one = new One {data="???"};
   Console.WriteLine(Array.BinarySearch(manies, one));

我得到的输出:

Unhandled Exception: System.InvalidOperationException: Failed to compare two elements in the array. ---> System.ArgumentException: At least one object must implement IComparable.
   at System.Collections.Comparer.Compare(Object a, Object b)
   at System.Collections.Generic.ObjectComparer`1.Compare(T x, T y)
   at System.Collections.Generic.ArraySortHelper`1.InternalBinarySearch(T[] array, Int32 index, Int32 length, T value, IComparer`1 comparer)
   at System.Collections.Generic.ArraySortHelper`1.BinarySearch(T[] array, Int32 index, Int32 length, T value, IComparer`1 comparer)
   --- End of inner exception stack trace ---
   at System.Collections.Generic.ArraySortHelper`1.BinarySearch(T[] array, Int32 index, Int32 length, T value, IComparer`1 comparer)
   at System.Array.BinarySearch[T](T[] array, Int32 index, Int32 length, T value, IComparer`1 comparer)
   at System.Array.BinarySearch[T](T[] array, T value)
   at ConsoleApplication1.Prosram.Main(String[] args) in C:\Users\xxx\documents\visual studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\Program.cs:line xxx

BinarySearch的行为始终存在一个问题,即密钥的比较器从未真正执行过,即使MSDN文档说如果数组元素未实现IComparable就是这种情况。 .NET版本4.5中解决了此问题。

错误的堆栈跟踪中有一些线索显示出源自System.Collections.Comparer.Compare()的错误。 在.NET 4.5和.NET 4.0中查看此方法的.NET源代码,可以发现对该方法的实现方式进行了重要更改:

.NET 4.5:

public int Compare(Object a, Object b) {
    if (a == b) return 0;
    ...
    IComparable ia = a as IComparable; 
    if (ia != null)
        return ia.CompareTo(b); 

    IComparable ib = b as IComparable;
    if (ib != null) 
        return -ib.CompareTo(a);

    throw new ArgumentException(Environment.GetResourceString(
                                       "Argument_ImplementIComparable"));

.NET 4.0:

public int Compare(Object a, Object b) {
    if (a == b) return 0;
    ...
    IComparable ia = a as IComparable; 
    if (ia != null)
        return ia.CompareTo(b); 

    throw new ArgumentException(Environment.GetResourceString(
                                      "Argument_ImplementIComparable"));

在我们的例子中,我们想观察到键的比较器正在被调用,在这种情况下,键为b而数组中的元素为a

这意味着对于4.5之前的.NET版本,BinarySearch方法的MSDN文档不正确。 如果数组中的元素未实现IComparable ,则该方法不考虑键的Comparator ,因为该实现取决于Comparer实际执行的操作,而不是这样做,而是抛出ArgumentException 但是,在4.5版中,它的工作原理始终如BinarySearch

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM