InvocationHelper
using Castle.Core.Internal;
using Castle.DynamicProxy.Generators;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Castle.DynamicProxy.Internal
{
public static class InvocationHelper
{
private struct CacheKey : IEquatable<CacheKey>
{
public MethodInfo Method { get; }
public Type Type { get; }
public CacheKey(MethodInfo method, Type type)
{
Method = method;
Type = type;
}
public bool Equals(CacheKey other)
{
if ((object)Method == other.Method)
return (object)Type == other.Type;
return false;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
object obj2;
if ((obj2 = obj) is CacheKey) {
CacheKey other = (CacheKey)obj2;
return Equals(other);
}
return false;
}
public override int GetHashCode()
{
return (((Method != (MethodInfo)null) ? Method.GetHashCode() : 0) * 397) ^ ((Type != (Type)null) ? Type.GetHashCode() : 0);
}
}
private static readonly Dictionary<CacheKey, MethodInfo> cache = new Dictionary<CacheKey, MethodInfo>();
private static readonly Lock lock = Lock.Create();
public static MethodInfo GetMethodOnObject(object target, MethodInfo proxiedMethod)
{
if (target == null)
return null;
return GetMethodOnType(target.GetType(), proxiedMethod);
}
public static MethodInfo GetMethodOnType(Type type, MethodInfo proxiedMethod)
{
if (type == (Type)null)
throw new ArgumentNullException("type");
using (IUpgradeableLockHolder upgradeableLockHolder = lock.ForReadingUpgradeable()) {
MethodInfo fromCache = GetFromCache(proxiedMethod, type);
if (!(fromCache != (MethodInfo)null)) {
upgradeableLockHolder.Upgrade();
fromCache = GetFromCache(proxiedMethod, type);
if (!(fromCache != (MethodInfo)null)) {
fromCache = ObtainMethod(proxiedMethod, type);
PutToCache(proxiedMethod, type, fromCache);
return fromCache;
}
return fromCache;
}
return fromCache;
}
}
private static MethodInfo GetFromCache(MethodInfo methodInfo, Type type)
{
CacheKey key = new CacheKey(methodInfo, type);
cache.TryGetValue(key, out MethodInfo value);
return value;
}
private static MethodInfo ObtainMethod(MethodInfo proxiedMethod, Type type)
{
Type[] array = null;
if (proxiedMethod.IsGenericMethod) {
array = proxiedMethod.GetGenericArguments();
proxiedMethod = proxiedMethod.GetGenericMethodDefinition();
}
Type declaringType = proxiedMethod.DeclaringType;
MethodInfo methodInfo = null;
if (declaringType.GetTypeInfo().IsInterface) {
InterfaceMapping runtimeInterfaceMap = type.GetTypeInfo().GetRuntimeInterfaceMap(declaringType);
int num = Array.IndexOf(runtimeInterfaceMap.InterfaceMethods, proxiedMethod);
methodInfo = runtimeInterfaceMap.TargetMethods[num];
} else {
MethodInfo[] allInstanceMethods = MethodFinder.GetAllInstanceMethods(type, BindingFlags.Public | BindingFlags.NonPublic);
foreach (MethodInfo methodInfo2 in allInstanceMethods) {
if (MethodSignatureComparer.Instance.Equals(methodInfo2.GetBaseDefinition(), proxiedMethod)) {
methodInfo = methodInfo2;
break;
}
}
}
if (methodInfo == (MethodInfo)null)
throw new ArgumentException($"""{proxiedMethod}""{type}""");
if (array == null)
return methodInfo;
return methodInfo.MakeGenericMethod(array);
}
private static void PutToCache(MethodInfo methodInfo, Type type, MethodInfo value)
{
CacheKey key = new CacheKey(methodInfo, type);
cache.Add(key, value);
}
}
}