默认比较器如何在C#中工作?

我使用OrderBy进行一些基于属性的排序,我找到了默认比较器的文档,但是它并没有给我很多解释。 如果一个对象没有实现System.IComparable<T> ,它如何生成一个Comparer<T>

例如,我目前正在基于object类型的属性值对object列表进行排序。 它们是下面的数字类型,排序工作正常。 C#/ Linq如何知道如何对对象进行排序? 它是否会对原始语言进行一些解锁操作? 它做了一些散列检查吗? 这将如何转化为大于或小于?

如果它们是一个更复杂的类型,那么这会失败并出现错误,或者OrderBy会无所作为,或者它会以一种毫无意义的方式排序?


那么你可以检查参考源,并亲自看看它的功能。

    public static Comparer<T> Default {
        get {
            Contract.Ensures(Contract.Result<Comparer<T>>() != null);

            Comparer<T> comparer = defaultComparer;
            if (comparer == null) {
                comparer = CreateComparer();
                defaultComparer = comparer;
            }
            return comparer;
        }
    }
    private static Comparer<T> CreateComparer() {
        RuntimeType t = (RuntimeType)typeof(T);

        // If T implements IComparable<T> return a GenericComparer<T>
#if FEATURE_LEGACYNETCF
        //(SNITP)
#endif
            if (typeof(IComparable<T>).IsAssignableFrom(t)) {
                return (Comparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericComparer<int>), t);
            }

        // If T is a Nullable<U> where U implements IComparable<U> return a NullableComparer<U>
        if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) {
            RuntimeType u = (RuntimeType)t.GetGenericArguments()[0];
            if (typeof(IComparable<>).MakeGenericType(u).IsAssignableFrom(u)) {
                return (Comparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableComparer<int>), u);
            }
        }
        // Otherwise return an ObjectComparer<T>
      return new ObjectComparer<T>();
    }

因此,它会检查类型是否实现了IComparable<T> ,如果它使用内置于该类型的比较器(您的数组类型的对象列表将遵循此分支)。 然后在类型为Nullable<ICompareable<T>>情况下再次执行相同的检查。 如果这也失败了,它使用使用Comparer.DefaultObjectComparer

这是Comparer.Default的比较代码

    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);

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

正如你所看到的,它会检查ab实现IComparable ,如果两者都不抛出异常。


在参考源上浏览时,它会返回一个ObjectComparer<T> ,它是一个特殊的内部类型,它将工作委托给System.Collections.Comparer.Default

如果它接收到不实现IComparable参数,则会反过来引发异常。 由于该比较器通过向下转换和反射进行工作,因此它不关心对象的静态类型是否未实现IComparable (如果有object列表,则是这种情况)。

所以底线是这样的:首先它检查IComparable<T> ,然后检查IComparable ,最后它会抛出一个异常。

顺便说一下,大多数(我甚至说都是)内置类型以某种方式实现了IComparable<T> ,所以这就是它们如何进行排序。


int ,或者更确切地说, Int32确实实现了IComparable ,所以它可以工作。 (资源)

OrderBy似乎试图将比较器用于它遇到的第一个类型,所以如果您从一个没有实现IComparable的对象开始,您将得到一个ArgumentException

至少有一个对象必须实现IComparable

如果你开始说一个Int32 ,那么你将得到相同的异常:

对象必须是Int32类型

来自Int32的比较器

链接地址: http://www.djcxy.com/p/27995.html

上一篇: How does the default comparator work in C#?

下一篇: Calling MVC view from asp.net class throws exception