Optimize DynamicProxy

pull/357/head
NextTurn 2018-12-04 00:00:00 +08:00
parent eb96c4a2a2
commit 08da959737
No known key found for this signature in database
GPG Key ID: 17A0D50ADDE1A0C4
2 changed files with 46 additions and 207 deletions

View File

@ -19,196 +19,63 @@ namespace DynamicProxy
}
/// <summary>
/// Factory class used to cache Types instances
/// </summary>
public class MetaDataFactory
public static class ProxyFactory
{
private static readonly Dictionary<string, Type> typeMap = new Dictionary<string, Type>();
/// <summary>
/// Class constructor. Private because this is a static class.
/// </summary>
private MetaDataFactory()
{
}
///<summary>
/// Method to add a new Type to the cache, using the type's fully qualified
/// name as the key
///</summary>
///<param name="interfaceType">Type to cache</param>
public static void Add(Type interfaceType)
{
if (interfaceType != null)
{
lock (typeMap)
{
#if NETCOREAPP
_ = typeMap.TryAdd(interfaceType.FullName!, interfaceType);
#else
if (!typeMap.ContainsKey(interfaceType.FullName!))
{
typeMap.Add(interfaceType.FullName!, interfaceType);
}
#endif
}
}
}
///<summary>
/// Method to return the method of a given type at a specified index.
///</summary>
///<param name="name">Fully qualified name of the method to return</param>
///<param name="i">Index to use to return MethodInfo</param>
///<returns>MethodInfo</returns>
public static MethodInfo GetMethod(string name, int i)
{
Type? type = null;
lock (typeMap)
{
type = typeMap[name];
}
return type.GetMethods()[i];
}
public static PropertyInfo GetProperty(string name, int i)
{
Type? type = null;
lock (typeMap)
{
type = typeMap[name];
}
return type.GetProperties()[i];
}
}
/// <summary>
/// </summary>
public class ProxyFactory
{
private static ProxyFactory? _instance;
private static readonly object LockObj = new object();
private readonly Dictionary<string, Type> _typeMap = new Dictionary<string, Type>();
private static readonly Dictionary<Type, OpCode> OpCodeTypeMapper = new Dictionary<Type, OpCode>
{
{ typeof(bool), OpCodes.Ldind_I1 },
{ typeof(short), OpCodes.Ldind_I2 },
{ typeof(int), OpCodes.Ldind_I4 },
{ typeof(long), OpCodes.Ldind_I8 },
{ typeof(double), OpCodes.Ldind_R8 },
{ typeof(float), OpCodes.Ldind_R4 },
{ typeof(ushort), OpCodes.Ldind_U2 },
{ typeof(uint), OpCodes.Ldind_U4 },
};
private const string ProxySuffix = "Proxy";
private const string AssemblyName = "ProxyAssembly";
private const string ModuleName = "ProxyModule";
private const string HandlerName = "handler";
private ProxyFactory()
{
}
private static readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
public static ProxyFactory GetInstance()
{
if (_instance == null)
{
CreateInstance();
}
private static readonly AssemblyBuilder AssemblyBuilder =
#if VNEXT
AssemblyBuilder.DefineDynamicAssembly(
#else
AppDomain.CurrentDomain.DefineDynamicAssembly(
#endif
new AssemblyName(AssemblyName), AssemblyBuilderAccess.Run);
return _instance!;
}
private static readonly ModuleBuilder ModuleBuilder = AssemblyBuilder.DefineDynamicModule(ModuleName);
private static void CreateInstance()
{
lock (LockObj)
{
_instance ??= new ProxyFactory();
}
}
public object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface)
public static object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface = false)
{
string typeName = objType.FullName + ProxySuffix;
Type? type = null;
lock (_typeMap)
lock (TypeCache)
{
_ = _typeMap.TryGetValue(typeName, out type);
}
// check to see if the type was in the cache. If the type was not cached, then
// create a new instance of the dynamic type and add it to the cache.
if (type == null)
{
if (isObjInterface)
if (!TypeCache.TryGetValue(typeName, out type))
{
type = CreateType(handler, new Type[] { objType }, typeName);
}
else
{
type = CreateType(handler, objType.GetInterfaces(), typeName);
}
lock (_typeMap)
{
_typeMap.Add(typeName, type);
type = CreateType(typeName, isObjInterface ? new Type[] { objType } : objType.GetInterfaces());
TypeCache.Add(typeName, type);
}
}
// return a new instance of the type.
return Activator.CreateInstance(type, new object[] { handler })!;
}
public object Create(IProxyInvocationHandler handler, Type objType)
{
return Create(handler, objType, false);
}
private Type CreateType(IProxyInvocationHandler handler, Type[] interfaces, string dynamicTypeName)
private static Type CreateType(string dynamicTypeName, Type[] interfaces)
{
Type objType = typeof(object);
Type handlerType = typeof(IProxyInvocationHandler);
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = AssemblyName;
assemblyName.Version = new Version(1, 0, 0, 0);
// create a new assembly for this proxy, one that isn't presisted on the file system
AssemblyBuilder assemblyBuilder =
#if VNEXT
AssemblyBuilder.DefineDynamicAssembly(
#else
AppDomain.CurrentDomain.DefineDynamicAssembly(
#endif
assemblyName, AssemblyBuilderAccess.Run);
// create a new module for this proxy
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(ModuleName);
// Set the class to be public and sealed
TypeAttributes typeAttributes =
TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed;
TypeAttributes typeAttributes = TypeAttributes.Public | TypeAttributes.Sealed;
// Gather up the proxy information and create a new type builder. One that
// inherits from Object and implements the interface passed in
TypeBuilder typeBuilder = moduleBuilder.DefineType(
TypeBuilder typeBuilder = ModuleBuilder.DefineType(
dynamicTypeName, typeAttributes, objType, interfaces);
// Define a member variable to hold the delegate
FieldBuilder handlerField = typeBuilder.DefineField(
HandlerName, handlerType, FieldAttributes.Private);
HandlerName, handlerType, FieldAttributes.Private | FieldAttributes.InitOnly);
// build a constructor that takes the delegate object as the only argument
ConstructorInfo baseConstructor = objType.GetConstructor(Type.EmptyTypes)!;
ConstructorBuilder delegateConstructor = typeBuilder.DefineConstructor(
MethodAttributes.Public, CallingConventions.Standard, new Type[] { handlerType });
#region( "Constructor IL Code" )
ILGenerator constructorIL = delegateConstructor.GetILGenerator();
// Load "this"
@ -223,7 +90,6 @@ namespace DynamicProxy
constructorIL.Emit(OpCodes.Call, baseConstructor);
// Constructor return
constructorIL.Emit(OpCodes.Ret);
#endregion
// for every method that the interfaces define, build a corresponding
// method in the dynamic type that calls the handlers invoke method.
@ -235,14 +101,19 @@ namespace DynamicProxy
return typeBuilder.CreateType()!;
}
private static readonly MethodInfo INVOKE_METHOD = typeof(IProxyInvocationHandler).GetMethod(nameof(IProxyInvocationHandler.Invoke))!;
private static readonly MethodInfo GET_METHODINFO_METHOD = typeof(MetaDataFactory).GetMethod(nameof(MetaDataFactory.GetMethod))!;
/// <summary>
/// <see cref="IProxyInvocationHandler.Invoke(object, MethodInfo, object[])"/>.
/// </summary>
private static readonly MethodInfo InvokeMethod = typeof(IProxyInvocationHandler).GetMethod(nameof(IProxyInvocationHandler.Invoke))!;
private void GenerateMethod(Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder)
/// <summary>
/// <see cref="MethodBase.GetMethodFromHandle(RuntimeMethodHandle)"/>.
/// </summary>
private static readonly MethodInfo GetMethodFromHandleMethod = typeof(MethodBase).GetMethod(nameof(MethodBase.GetMethodFromHandle), new[] { typeof(RuntimeMethodHandle) })!;
private static void GenerateMethod(Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder)
{
MetaDataFactory.Add(interfaceType);
MethodInfo[] interfaceMethods = interfaceType.GetMethods();
// PropertyInfo[] props = interfaceType.GetProperties();
for (int i = 0; i < interfaceMethods.Length; i++)
{
@ -267,36 +138,31 @@ namespace DynamicProxy
CallingConventions.Standard,
methodInfo.ReturnType, methodParameters);
#region( "Handler Method IL Code" )
ILGenerator methodIL = methodBuilder.GetILGenerator();
// load "this"
// invoke target: IProxyInvocationHandler
methodIL.Emit(OpCodes.Ldarg_0);
// load the handler
methodIL.Emit(OpCodes.Ldfld, handlerField);
// load "this" since its needed for the call to invoke
methodIL.Emit(OpCodes.Ldarg_0);
// load the name of the interface, used to get the MethodInfo object
// from MetaDataFactory
methodIL.Emit(OpCodes.Ldstr, interfaceType.FullName!);
// load the index, used to get the MethodInfo object
// from MetaDataFactory
methodIL.Emit(OpCodes.Ldc_I4, i);
// invoke GetMethod in MetaDataFactory
methodIL.Emit(OpCodes.Call, GET_METHODINFO_METHOD);
// load the number of parameters onto the stack
// 1st parameter: object proxy
methodIL.Emit(OpCodes.Ldarg_0);
// 2nd parameter: MethodInfo method
methodIL.Emit(OpCodes.Ldtoken, methodInfo);
methodIL.Emit(OpCodes.Call, GetMethodFromHandleMethod);
methodIL.Emit(OpCodes.Castclass, typeof(MethodInfo));
// 3rd parameter: object[] parameters
methodIL.Emit(OpCodes.Ldc_I4, numOfParams);
// create a new array, using the size that was just pused on the stack
methodIL.Emit(OpCodes.Newarr, typeof(object));
// if we have any parameters, then iterate through and set the values
// of each element to the corresponding arguments
for (int j = 0; j < numOfParams; j++)
{
methodIL.Emit(OpCodes.Dup); // this copies the array
methodIL.Emit(OpCodes.Dup); // copy the array
methodIL.Emit(OpCodes.Ldc_I4, j);
methodIL.Emit(OpCodes.Ldarg, j + 1);
methodIL.Emit(OpCodes.Ldarg, j + 1); // +1 for "this"
if (methodParameters[j].IsValueType)
{
methodIL.Emit(OpCodes.Box, methodParameters[j]);
@ -306,28 +172,11 @@ namespace DynamicProxy
}
// call the Invoke method
methodIL.Emit(OpCodes.Callvirt, INVOKE_METHOD);
methodIL.Emit(OpCodes.Callvirt, InvokeMethod);
if (methodInfo.ReturnType != typeof(void))
{
// if the return type is a value type, then unbox the return value
// so that we don't get junk.
if (methodInfo.ReturnType.IsValueType)
{
methodIL.Emit(OpCodes.Unbox, methodInfo.ReturnType);
if (methodInfo.ReturnType.IsEnum)
{
methodIL.Emit(OpCodes.Ldind_I4);
}
else if (!methodInfo.ReturnType.IsPrimitive)
{
methodIL.Emit(OpCodes.Ldobj, methodInfo.ReturnType);
}
else
{
methodIL.Emit(OpCodeTypeMapper[methodInfo.ReturnType]);
}
}
methodIL.Emit(OpCodes.Unbox_Any, methodInfo.ReturnType);
}
else
{
@ -338,18 +187,8 @@ namespace DynamicProxy
// Return
methodIL.Emit(OpCodes.Ret);
#endregion
}
// for (int i = 0; i < props.Length; i++)
// {
// PropertyInfo p = props[i];
// PropertyBuilder pb = typeBuilder.DefineProperty(p.Name, p.Attributes, p.PropertyType, new Type[] { p.PropertyType });
// pb.SetGetMethod((MethodBuilder)methodTable[p.GetGetMethod()]);
// pb.SetSetMethod((MethodBuilder)methodTable[p.GetSetMethod()]);
// }
// Iterate through the parent interfaces and recursively call this method
foreach (Type parentType in interfaceType.GetInterfaces())
{

View File

@ -289,7 +289,7 @@ namespace WMI
// TODO: support collections
foreach (CimInstance cimInstance in this.cimSession.QueryInstances(CimNamespace, "WQL", query))
{
return ProxyFactory.GetInstance().Create(new InstanceHandler(this.cimSession, cimInstance), method.ReturnType, true);
return ProxyFactory.Create(new InstanceHandler(this.cimSession, cimInstance), method.ReturnType, true);
}
#else
using ManagementObjectSearcher searcher = new ManagementObjectSearcher(this.wmiClass.Scope, new ObjectQuery(query));
@ -297,7 +297,7 @@ namespace WMI
// TODO: support collections
foreach (ManagementObject wmiObject in results)
{
return ProxyFactory.GetInstance().Create(new InstanceHandler(wmiObject), method.ReturnType, true);
return ProxyFactory.Create(new InstanceHandler(wmiObject), method.ReturnType, true);
}
#endif
@ -327,7 +327,7 @@ namespace WMI
{
WmiClassName className = (WmiClassName)typeof(T).GetCustomAttributes(typeof(WmiClassName), false)[0];
return (T)ProxyFactory.GetInstance().Create(
return (T)ProxyFactory.Create(
#if FEATURE_CIM
new ClassHandler(this.cimSession, className.Name),
#else