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);
MethodInfo method = typeFromHandle.GetMethod("HasSameMetadataDefinitionAs", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.ExactBinding, null, new Type[1] {
typeof(MemberInfo)
}, null);
if (method != (MethodInfo)null) {
Func<MemberInfo, MemberInfo, bool> func = (Func<MemberInfo, MemberInfo, bool>)method.CreateDelegate(typeof(Func<MemberInfo, MemberInfo, bool>));
try {
bool result = func(m1, m2);
s_MemberEquivalence = func;
return result;
} catch {
}
}
PropertyInfo property = typeFromHandle.GetProperty("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> func2 = Expression.Lambda<Func<MemberInfo, MemberInfo, bool>>(Expression.Equal(Expression.Property(parameterExpression, property), Expression.Property(parameterExpression2, property)), new ParameterExpression[2] {
parameterExpression,
parameterExpression2
}).Compile();
bool result2 = func2(m1, m2);
s_MemberEquivalence = func2;
return result2;
}
} catch {
}
return (s_MemberEquivalence = ((MemberInfo m1param, MemberInfo m2param) => m1param.IsEquivalentTo(m2param)))(m1, m2);
};
public static bool IsNullableType(this Type type)
{
if (type.IsConstructedGenericType)
return type.GetGenericTypeDefinition() == typeof(Nullable<>);
return false;
}
public static bool IsEquivalentTo(this MemberInfo mi1, MemberInfo mi2)
{
if (mi1 == (MemberInfo)null || mi2 == (MemberInfo)null) {
if (mi1 == (MemberInfo)null)
return mi2 == (MemberInfo)null;
return false;
}
if (mi1.Equals(mi2))
return true;
MethodInfo methodInfo = mi1 as MethodInfo;
if ((object)methodInfo != null) {
MethodInfo methodInfo2 = mi2 as MethodInfo;
if ((object)methodInfo2 == null || methodInfo.IsGenericMethod != methodInfo2.IsGenericMethod)
return false;
if (methodInfo.IsGenericMethod) {
methodInfo = methodInfo.GetGenericMethodDefinition();
methodInfo2 = methodInfo2.GetGenericMethodDefinition();
if (methodInfo.GetGenericArguments().Length != methodInfo2.GetGenericArguments().Length)
return false;
}
if (methodInfo != methodInfo2 && methodInfo.CallingConvention == methodInfo2.CallingConvention && methodInfo.Name == methodInfo2.Name && methodInfo.DeclaringType.IsGenericallyEqual(methodInfo2.DeclaringType) && methodInfo.ReturnType.IsGenericallyEquivalentTo(methodInfo2.ReturnType, methodInfo, methodInfo2))
return methodInfo.AreParametersEquivalent(methodInfo2);
return false;
}
ConstructorInfo constructorInfo = mi1 as ConstructorInfo;
if ((object)constructorInfo != null) {
ConstructorInfo constructorInfo2 = mi2 as ConstructorInfo;
if ((object)constructorInfo2 != null && constructorInfo != constructorInfo2 && constructorInfo.CallingConvention == constructorInfo2.CallingConvention && constructorInfo.DeclaringType.IsGenericallyEqual(constructorInfo2.DeclaringType))
return constructorInfo.AreParametersEquivalent(constructorInfo2);
return false;
}
PropertyInfo propertyInfo = mi1 as PropertyInfo;
if ((object)propertyInfo != null) {
PropertyInfo propertyInfo2 = mi2 as PropertyInfo;
if ((object)propertyInfo2 != null && propertyInfo != propertyInfo2 && propertyInfo.Name == propertyInfo2.Name && propertyInfo.DeclaringType.IsGenericallyEqual(propertyInfo2.DeclaringType) && propertyInfo.PropertyType.IsGenericallyEquivalentTo(propertyInfo2.PropertyType, propertyInfo, propertyInfo2) && propertyInfo.GetGetMethod(true).IsEquivalentTo(propertyInfo2.GetGetMethod(true)))
return propertyInfo.GetSetMethod(true).IsEquivalentTo(propertyInfo2.GetSetMethod(true));
}
return false;
}
private static bool AreParametersEquivalent(this MethodBase method1, MethodBase method2)
{
ParameterInfo[] parameters = method1.GetParameters();
ParameterInfo[] parameters2 = method2.GetParameters();
if (parameters.Length != parameters2.Length)
return false;
for (int i = 0; i < parameters.Length; i++) {
if (!parameters[i].IsEquivalentTo(parameters2[i], method1, method2))
return false;
}
return true;
}
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 (t1 == (Type)null || t2 == (Type)null) {
if (t1 == (Type)null)
return t2 == (Type)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 (t1.DeclaringMethod == (MethodBase)null && member1.DeclaringType.Equals(t1.DeclaringType)) {
if (!(t2.DeclaringMethod == (MethodBase)null) || !member2.DeclaringType.Equals(t2.DeclaringType))
return t1.IsTypeParameterEquivalentToTypeInst(t2, member2);
} else if (t2.DeclaringMethod == (MethodBase)null && member2.DeclaringType.Equals(t2.DeclaringType)) {
return t2.IsTypeParameterEquivalentToTypeInst(t1, member1);
}
return false;
}
return t1.IsTypeParameterEquivalentToTypeInst(t2, member2);
}
if (t2.IsGenericParameter)
return t2.IsTypeParameterEquivalentToTypeInst(t1, member1);
if (t1.IsGenericType && t2.IsGenericType) {
Type[] genericArguments = t1.GetGenericArguments();
Type[] genericArguments2 = t2.GetGenericArguments();
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 (typeParam.DeclaringMethod != (MethodBase)null) {
if (!(member is MethodBase))
return false;
MethodBase methodBase = (MethodBase)member;
int genericParameterPosition = typeParam.GenericParameterPosition;
Type[] array = methodBase.IsGenericMethod ? methodBase.GetGenericArguments() : null;
if (array != null && array.Length > genericParameterPosition)
return array[genericParameterPosition].Equals(typeInst);
return false;
}
return member.DeclaringType.GetGenericArguments()[typeParam.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;
}
public static string GetIndexerName(this Type type)
{
string typeIndexerName = GetTypeIndexerName(type);
if (typeIndexerName == null && type.IsInterface) {
Type[] interfaces = type.GetInterfaces();
foreach (Type type2 in interfaces) {
typeIndexerName = GetTypeIndexerName(type2);
if (typeIndexerName != null)
break;
}
}
return typeIndexerName;
}
private static string GetTypeIndexerName(Type type)
{
string name = type.GetCustomAttribute<DefaultMemberAttribute>()?.MemberName;
if (name != null && type.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Any(delegate(PropertyInfo p) {
if (p.Name == name)
return p.GetIndexParameters().Length != 0;
return false;
}))
return name;
return null;
}
}
}