// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
using static System.RuntimeTypeHandle;
namespace System.Collections.Generic
{
///
/// Helper class for creating the default and .
///
///
/// This class is intentionally type-unsafe and non-generic to minimize the generic instantiation overhead of creating
/// the default comparer/equality comparer for a new type parameter. Efficiency of the methods in here does not matter too
/// much since they will only be run once per type parameter, but generic code involved in creating the comparers needs to be
/// kept to a minimum.
///
internal static class ComparerHelpers
{
///
/// Creates the default .
///
/// The type to create the default comparer for.
///
/// The logic in this method is replicated in vm/compile.cpp to ensure that NGen saves the right instantiations.
///
internal static object CreateDefaultComparer(Type type)
{
Debug.Assert(type != null && type is RuntimeType);
object result = null;
var runtimeType = (RuntimeType)type;
// If T implements IComparable return a GenericComparer
if (typeof(IComparable<>).MakeGenericType(type).IsAssignableFrom(type))
{
result = CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericComparer), runtimeType);
}
// Nullable does not implement IComparable directly because that would add an extra interface call per comparison.
// Instead, it relies on Comparer.Default to specialize for nullables and do the lifted comparisons if T implements IComparable.
else if (type.IsGenericType)
{
if (type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
result = TryCreateNullableComparer(runtimeType);
}
}
// The comparer for enums is specialized to avoid boxing.
else if (type.IsEnum)
{
result = TryCreateEnumComparer(runtimeType);
}
return result ?? CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(ObjectComparer