// this function utilizes the template type loader to generate new // EqualityComparer types on the fly private static object GetComparer(RuntimeTypeHandle t) { RuntimeTypeHandle comparerType; RuntimeTypeHandle openComparerType = default(RuntimeTypeHandle); RuntimeTypeHandle comparerTypeArgument = default(RuntimeTypeHandle); if (RuntimeAugments.IsNullable(t)) { RuntimeTypeHandle nullableType = RuntimeAugments.GetNullableType(t); if (ImplementsIEquatable(nullableType)) { openComparerType = typeof(NullableEqualityComparer <>).TypeHandle; comparerTypeArgument = nullableType; } } if (IsEnum(t)) { openComparerType = typeof(EnumEqualityComparer <>).TypeHandle; comparerTypeArgument = t; } if (openComparerType.Equals(default(RuntimeTypeHandle))) { if (ImplementsIEquatable(t)) { openComparerType = typeof(GenericEqualityComparer <>).TypeHandle; comparerTypeArgument = t; } else { openComparerType = typeof(ObjectEqualityComparer <>).TypeHandle; comparerTypeArgument = t; } } bool success = RuntimeAugments.TypeLoaderCallbacks.TryGetConstructedGenericTypeForComponents(openComparerType, new RuntimeTypeHandle[] { comparerTypeArgument }, out comparerType); if (!success) { Environment.FailFast("Unable to create comparer"); } return(RuntimeAugments.NewObject(comparerType)); }
public sealed override Object Invoke(Object thisObject, Object[] arguments) { Object value = thisObject; bool hasValue = (thisObject != null); switch (_id) { case NullableMethodId.GetType: CheckArgumentCount(arguments, 0); return(value.GetType()); // Note: this throws a NullReferenceException if hasValue is false. Well so does the desktop. case NullableMethodId.ToString: CheckArgumentCount(arguments, 0); return(hasValue ? value.ToString() : ""); case NullableMethodId.Equals: { CheckArgumentCount(arguments, 1); Object other = arguments[0]; if (!hasValue) { return(other == null); } if (other == null) { return(false); } return(value.Equals(other)); } case NullableMethodId.GetHashCode: CheckArgumentCount(arguments, 0); return(hasValue ? value.GetHashCode() : 0); case NullableMethodId.Ctor: { // Constructor case is tricky. Our implementation of NewObject() does not accept Nullable<T>'s so this is one of those cases // where the constructor is responsible for both the allocation and initialization. Fortunately, we only have to return the boxed // version of Nullable<T> which conveniently happens to be equal to the value we were passed in. CheckArgumentCount(arguments, 1); RuntimeTypeHandle theT = RuntimeAugments.GetNullableType(_nullableTypeHandle); Object argument = RuntimeAugments.CheckArgument(arguments[0], theT); return(argument); } case NullableMethodId.get_HasValue: CheckArgumentCount(arguments, 0); return(hasValue); case NullableMethodId.get_Value: CheckArgumentCount(arguments, 0); if (!hasValue) { throw new InvalidOperationException(SR.InvalidOperation_NoValue); } return(value); case NullableMethodId.GetValueOrDefault_0: { CheckArgumentCount(arguments, 0); if (hasValue) { return(value); } RuntimeTypeHandle theT = RuntimeAugments.GetNullableType(_nullableTypeHandle); return(RuntimeAugments.NewObject(theT)); } case NullableMethodId.GetValueOrDefault_1: { CheckArgumentCount(arguments, 1); RuntimeTypeHandle theT = RuntimeAugments.GetNullableType(_nullableTypeHandle); Object defaultValue = RuntimeAugments.CheckArgument(arguments[0], theT); return(hasValue ? value : defaultValue); } default: throw new InvalidOperationException(); } }