<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />

RuntimeBinderExtensions

using System; using System.Linq; using System.Linq.Expressions; using System.Reflection; namespace Microsoft.CSharp.RuntimeBinder { internal static class RuntimeBinderExtensions { private static Func<MemberInfo, MemberInfo, bool> s_MemberEquivalence = delegate(MemberInfo m1, MemberInfo m2) { try { Type typeFromHandle = typeof(MemberInfo); PropertyInfo property = TypeExtensions.GetProperty(typeFromHandle, "MetadataToken", typeof(int), Array.Empty<Type>()); if ((object)property != null && property.CanRead) { ParameterExpression parameterExpression = Expression.Parameter(typeFromHandle); ParameterExpression parameterExpression2 = Expression.Parameter(typeFromHandle); Func<MemberInfo, MemberInfo, bool> func = Expression.Lambda<Func<MemberInfo, MemberInfo, bool>>(Expression.Equal(Expression.Property(parameterExpression, property), Expression.Property(parameterExpression2, property)), new ParameterExpression[2] { parameterExpression, parameterExpression2 }).Compile(); bool result = func(m1, m2); s_MemberEquivalence = func; return result; } } catch { } return (s_MemberEquivalence = ((MemberInfo m1param, MemberInfo m2param) => m1param.IsEquivalentTo(m2param)))(m1, m2); }; public static bool IsEquivalentTo(this Type t1, Type t2) { return (object)t1 == t2; } public static bool IsNullableType(this Type type) { if (type.IsConstructedGenericType) return (object)type.GetGenericTypeDefinition() == typeof(Nullable<>); return false; } public static TypeCode GetTypeCode(this Type type) { if ((object)type == null) return TypeCode.Empty; if ((object)type == typeof(bool)) return TypeCode.Boolean; if ((object)type == typeof(char)) return TypeCode.Char; if ((object)type == typeof(sbyte)) return TypeCode.SByte; if ((object)type == typeof(byte)) return TypeCode.Byte; if ((object)type == typeof(short)) return TypeCode.Int16; if ((object)type == typeof(ushort)) return TypeCode.UInt16; if ((object)type == typeof(int)) return TypeCode.Int32; if ((object)type == typeof(uint)) return TypeCode.UInt32; if ((object)type == typeof(long)) return TypeCode.Int64; if ((object)type == typeof(ulong)) return TypeCode.UInt64; if ((object)type == typeof(float)) return TypeCode.Single; if ((object)type == typeof(double)) return TypeCode.Double; if ((object)type == typeof(decimal)) return TypeCode.Decimal; if ((object)type == typeof(DateTime)) return TypeCode.DateTime; if ((object)type == typeof(string)) return TypeCode.String; if (type.GetTypeInfo().get_IsEnum()) return Enum.GetUnderlyingType(type).GetTypeCode(); return TypeCode.Object; } public static bool IsEquivalentTo(this MemberInfo mi1, MemberInfo mi2) { if ((object)mi1 == null || (object)mi2 == null) { if ((object)mi1 == null) return (object)mi2 == null; return false; } if (mi1.Equals(mi2)) return true; if (mi1 is MethodInfo && mi2 is MethodInfo) { MethodInfo method3 = mi1 as MethodInfo; MethodInfo method2 = mi2 as MethodInfo; if (method3.IsGenericMethod != method2.IsGenericMethod) return false; if (method3.IsGenericMethod) { method3 = method3.GetGenericMethodDefinition(); method2 = method2.GetGenericMethodDefinition(); if (method3.GetGenericArguments().Length != method2.GetGenericArguments().Length) return false; } ParameterInfo[] parameters; ParameterInfo[] parameters2; if ((object)method3 != method2 && method3.Name == method2.Name && method3.DeclaringType.IsGenericallyEqual(method2.DeclaringType) && method3.ReturnType.IsGenericallyEquivalentTo(method2.ReturnType, method3, method2) && (parameters = method3.GetParameters()).Length == (parameters2 = method2.GetParameters()).Length) return parameters.Zip(parameters2, (ParameterInfo pi1, ParameterInfo pi2) => pi1.IsEquivalentTo(pi2, method3, method2)).All((bool x) => x); return false; } if (mi1 is ConstructorInfo && mi2 is ConstructorInfo) { ConstructorInfo ctor3 = mi1 as ConstructorInfo; ConstructorInfo ctor2 = mi2 as ConstructorInfo; ParameterInfo[] parameters3; ParameterInfo[] parameters4; if ((object)ctor3 != ctor2 && ctor3.DeclaringType.IsGenericallyEqual(ctor2.DeclaringType) && (parameters3 = ctor3.GetParameters()).Length == (parameters4 = ctor2.GetParameters()).Length) return parameters3.Zip(parameters4, (ParameterInfo pi1, ParameterInfo pi2) => pi1.IsEquivalentTo(pi2, ctor3, ctor2)).All((bool x) => x); return false; } if (mi1 is PropertyInfo && mi2 is PropertyInfo) { PropertyInfo propertyInfo = mi1 as PropertyInfo; PropertyInfo propertyInfo2 = mi2 as PropertyInfo; if ((object)propertyInfo != propertyInfo2 && propertyInfo.Name == propertyInfo2.Name && propertyInfo.DeclaringType.IsGenericallyEqual(propertyInfo2.DeclaringType) && propertyInfo.PropertyType.IsGenericallyEquivalentTo(propertyInfo2.PropertyType, propertyInfo, propertyInfo2) && PropertyInfoExtensions.GetGetMethod(propertyInfo, true).IsEquivalentTo(PropertyInfoExtensions.GetGetMethod(propertyInfo2, true))) return PropertyInfoExtensions.GetSetMethod(propertyInfo, true).IsEquivalentTo(PropertyInfoExtensions.GetSetMethod(propertyInfo2, true)); return false; } return false; } private static bool IsEquivalentTo(this ParameterInfo pi1, ParameterInfo pi2, MethodBase method1, MethodBase method2) { if (pi1 == null || pi2 == null) { if (pi1 == null) return pi2 == null; return false; } if (pi1.Equals(pi2)) return true; return pi1.ParameterType.IsGenericallyEquivalentTo(pi2.ParameterType, method1, method2); } private static bool IsGenericallyEqual(this Type t1, Type t2) { if ((object)t1 == null || (object)t2 == null) { if ((object)t1 == null) return (object)t2 == null; return false; } if (t1.Equals(t2)) return true; if (t1.IsConstructedGenericType || t2.IsConstructedGenericType) { Type type = t1.IsConstructedGenericType ? t1.GetGenericTypeDefinition() : t1; Type o = t2.IsConstructedGenericType ? t2.GetGenericTypeDefinition() : t2; return type.Equals(o); } return false; } private static bool IsGenericallyEquivalentTo(this Type t1, Type t2, MemberInfo member1, MemberInfo member2) { if (t1.Equals(t2)) return true; if (t1.IsGenericParameter) { if (t2.IsGenericParameter) { if ((object)t1.GetTypeInfo().get_DeclaringMethod() == null && member1.DeclaringType.Equals(t1.GetTypeInfo().DeclaringType)) { if ((object)t2.GetTypeInfo().get_DeclaringMethod() != null || !member2.DeclaringType.Equals(t2.GetTypeInfo().DeclaringType)) return t1.IsTypeParameterEquivalentToTypeInst(t2, member2); } else if ((object)t2.GetTypeInfo().get_DeclaringMethod() == null && member2.DeclaringType.Equals(t2.GetTypeInfo().DeclaringType)) { return t2.IsTypeParameterEquivalentToTypeInst(t1, member1); } return false; } return t1.IsTypeParameterEquivalentToTypeInst(t2, member2); } if (t2.IsGenericParameter) return t2.IsTypeParameterEquivalentToTypeInst(t1, member1); if (t1.GetTypeInfo().get_IsGenericType() && t2.GetTypeInfo().get_IsGenericType()) { Type[] genericArguments = TypeExtensions.GetGenericArguments(t1); Type[] genericArguments2 = TypeExtensions.GetGenericArguments(t2); if (genericArguments.Length == genericArguments2.Length) { if (t1.IsGenericallyEqual(t2)) return genericArguments.Zip(genericArguments2, (Type ta1, Type ta2) => ta1.IsGenericallyEquivalentTo(ta2, member1, member2)).All((bool x) => x); return false; } } if (t1.IsArray && t2.IsArray) { if (t1.GetArrayRank() == t2.GetArrayRank()) return t1.GetElementType().IsGenericallyEquivalentTo(t2.GetElementType(), member1, member2); return false; } if ((t1.IsByRef && t2.IsByRef) || (t1.IsPointer && t2.IsPointer)) return t1.GetElementType().IsGenericallyEquivalentTo(t2.GetElementType(), member1, member2); return false; } private static bool IsTypeParameterEquivalentToTypeInst(this Type typeParam, Type typeInst, MemberInfo member) { if ((object)typeParam.GetTypeInfo().get_DeclaringMethod() != null) { if (!(member is MethodBase)) return false; MethodBase methodBase = (MethodBase)member; int genericParameterPosition = typeParam.GetTypeInfo().get_GenericParameterPosition(); Type[] array = methodBase.IsGenericMethod ? methodBase.GetGenericArguments() : null; if (array != null && array.Length > genericParameterPosition) return array[genericParameterPosition].Equals(typeInst); return false; } return TypeExtensions.GetGenericArguments(member.DeclaringType)[typeParam.GetTypeInfo().get_GenericParameterPosition()].Equals(typeInst); } public static bool HasSameMetadataDefinitionAs(this MemberInfo mi1, MemberInfo mi2) { if (mi1.Module.Equals(mi2.Module)) return s_MemberEquivalence(mi1, mi2); return false; } } }