| File: Microsoft\CSharp\RuntimeBinder\ComInterop\TypeUtils.cs | Web Access |
| Project: src\runtime\src\libraries\Microsoft.CSharp\src\Microsoft.CSharp.csproj (Microsoft.CSharp) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace Microsoft.CSharp.RuntimeBinder.ComInterop { internal static class TypeUtils { //CONFORMING internal static Type GetNonNullableType(Type type) { if (IsNullableType(type)) { return type.GetGenericArguments()[0]; } return type; } //CONFORMING internal static bool IsNullableType(this Type type) { return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); } //CONFORMING internal static bool AreReferenceAssignable(Type dest, Type src) { // WARNING: This actually implements "Is this identity assignable and/or reference assignable?" if (dest == src) { return true; } if (!dest.IsValueType && !src.IsValueType && AreAssignable(dest, src)) { return true; } return false; } //CONFORMING internal static bool AreAssignable(Type dest, Type src) { if (dest == src) { return true; } if (dest.IsAssignableFrom(src)) { return true; } if (dest.IsArray && src.IsArray && dest.GetArrayRank() == src.GetArrayRank() && AreReferenceAssignable(dest.GetElementType(), src.GetElementType())) { return true; } if (src.IsArray && dest.IsGenericType && (dest.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IEnumerable<>) || dest.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IList<>) || dest.GetGenericTypeDefinition() == typeof(System.Collections.Generic.ICollection<>)) && dest.GetGenericArguments()[0] == src.GetElementType()) { return true; } return false; } //CONFORMING internal static bool IsImplicitlyConvertible(Type source, Type destination) { return IsIdentityConversion(source, destination) || IsImplicitNumericConversion(source, destination) || IsImplicitReferenceConversion(source, destination) || IsImplicitBoxingConversion(source, destination); } [RequiresUnreferencedCode(Binder.TrimmerWarning)] internal static bool IsImplicitlyConvertible(Type source, Type destination, bool considerUserDefined) { return IsImplicitlyConvertible(source, destination) || (considerUserDefined && GetUserDefinedCoercionMethod(source, destination, true) != null); } //CONFORMING [RequiresUnreferencedCode(Binder.TrimmerWarning)] internal static MethodInfo GetUserDefinedCoercionMethod(Type convertFrom, Type convertToType, bool implicitOnly) { // check for implicit coercions first Type nnExprType = TypeUtils.GetNonNullableType(convertFrom); Type nnConvType = TypeUtils.GetNonNullableType(convertToType); // try exact match on types MethodInfo[] eMethods = nnExprType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo method = FindConversionOperator(eMethods, convertFrom, convertToType, implicitOnly); if (method != null) { return method; } MethodInfo[] cMethods = nnConvType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); method = FindConversionOperator(cMethods, convertFrom, convertToType, implicitOnly); if (method != null) { return method; } // try lifted conversion if (nnExprType != convertFrom || nnConvType != convertToType) { method = FindConversionOperator(eMethods, nnExprType, nnConvType, implicitOnly) ?? FindConversionOperator(cMethods, nnExprType, nnConvType, implicitOnly); if (method != null) { return method; } } return null; } //CONFORMING internal static MethodInfo FindConversionOperator(MethodInfo[] methods, Type typeFrom, Type typeTo, bool implicitOnly) { foreach (MethodInfo mi in methods) { if (mi.Name != "op_Implicit" && (implicitOnly || mi.Name != "op_Explicit")) continue; if (mi.ReturnType != typeTo) continue; ParameterInfo[] pis = mi.GetParameters(); if (pis[0].ParameterType != typeFrom) continue; return mi; } return null; } //CONFORMING private static bool IsIdentityConversion(Type source, Type destination) { return source == destination; } //CONFORMING private static bool IsImplicitNumericConversion(Type source, Type destination) { TypeCode tcSource = Type.GetTypeCode(source); TypeCode tcDest = Type.GetTypeCode(destination); switch (tcSource) { case TypeCode.SByte: switch (tcDest) { case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } return false; case TypeCode.Byte: switch (tcDest) { case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } return false; case TypeCode.Int16: switch (tcDest) { case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } return false; case TypeCode.UInt16: switch (tcDest) { case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } return false; case TypeCode.Int32: switch (tcDest) { case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } return false; case TypeCode.UInt32: switch (tcDest) { case TypeCode.UInt32: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } return false; case TypeCode.Int64: case TypeCode.UInt64: switch (tcDest) { case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } return false; case TypeCode.Char: switch (tcDest) { case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } return false; case TypeCode.Single: return (tcDest == TypeCode.Double); } return false; } //CONFORMING private static bool IsImplicitReferenceConversion(Type source, Type destination) { return AreAssignable(destination, source); } //CONFORMING private static bool IsImplicitBoxingConversion(Type source, Type destination) { if (source.IsValueType && (destination == typeof(object) || destination == typeof(System.ValueType))) return true; if (source.IsEnum && destination == typeof(System.Enum)) return true; return false; } } }