mirror of https://github.com/winsw/winsw
Optimize DynamicProxy
parent
eb96c4a2a2
commit
08da959737
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue