diff --git a/Smart.Resolver/Resolver/Builders/EmitFactoryBuilder.cs b/Smart.Resolver/Resolver/Builders/EmitFactoryBuilder.cs index e6b35a8..ec45749 100644 --- a/Smart.Resolver/Resolver/Builders/EmitFactoryBuilder.cs +++ b/Smart.Resolver/Resolver/Builders/EmitFactoryBuilder.cs @@ -1,7 +1,7 @@ namespace Smart.Resolver.Builders { using System; - using System.Linq; + using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; @@ -9,69 +9,19 @@ namespace Smart.Resolver.Builders public sealed class EmitFactoryBuilder : IFactoryBuilder { - private AssemblyBuilder assemblyBuilder; + private static readonly Action[] EmptyActions = new Action[0]; - private ModuleBuilder moduleBuilder; - - private int nextId = 1; - - private ModuleBuilder ModuleBuilder - { - get - { - if (moduleBuilder == null) - { - assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly( - new AssemblyName("EmitBuilderAssembly"), - AssemblyBuilderAccess.Run); - moduleBuilder = assemblyBuilder.DefineDynamicModule( - "EmitBuilderModule"); - } - - return moduleBuilder; - } - } - - private int GenerateId() - { - lock (assemblyBuilder) - { - return nextId++; - } - } + private readonly HolderBuilder holderBuilder = new HolderBuilder(); public Func CreateFactory(ConstructorInfo ci, Func[] factories, Action[] actions) { + var holder = holderBuilder.CreateHolder(factories, actions); + var holderType = holder?.GetType() ?? typeof(object); + var returnType = ci.DeclaringType.IsValueType ? typeof(object) : ci.DeclaringType; - // Define type - var typeBuilder = ModuleBuilder.DefineType( - $"{ci.DeclaringType.FullName}_Factory_{GenerateId()}", - TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.AnsiClass | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit); - - // Define field - var factoryFields = factories - .Select((t, i) => typeBuilder.DefineField( - $"factory{i}", - t.GetType(), - FieldAttributes.Public | FieldAttributes.InitOnly)) - .ToList(); - - var actionFields = actions - .Select((t, i) => typeBuilder.DefineField( - $"actions{i}", - t.GetType(), - FieldAttributes.Public | FieldAttributes.InitOnly)) - .ToList(); - - // Define method - var method = typeBuilder.DefineMethod( - "Create", - MethodAttributes.Public | MethodAttributes.HideBySig, - returnType, - new[] { typeof(IResolver) }); - - var ilGenerator = method.GetILGenerator(); + var dynamicMethod = new DynamicMethod(string.Empty, returnType, new[] { holderType, typeof(IResolver) }, true); + var ilGenerator = dynamicMethod.GetILGenerator(); for (var i = 0; i < factories.Length; i++) { @@ -83,8 +33,10 @@ public Func CreateFactory(ConstructorInfo ci, Func CreateFactory(ConstructorInfo ci, Func CreateFactory(ConstructorInfo ci, Func).MakeGenericType(typeof(IResolver), returnType); - // ReSharper disable once AssignNullToNotNullAttribute - return (Func)Delegate.CreateDelegate(funcType, instance, factoryType.GetMethod("Create")); + return (Func)dynamicMethod.CreateDelegate(funcType, holder); } public Func CreateArrayFactory(Type type, Func[] factories) { - var arrayType = type.MakeArrayType(); + var holder = holderBuilder.CreateHolder(factories, EmptyActions); + var holderType = holder?.GetType() ?? typeof(object); - // Define type - var typeBuilder = ModuleBuilder.DefineType( - $"{arrayType.FullName}_Factory_{GenerateId()}", - TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.AnsiClass | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit); - - // Define field - var fields = factories - .Select((t, i) => typeBuilder.DefineField( - $"factory{i}", - t.GetType(), - FieldAttributes.Public | FieldAttributes.InitOnly)) - .ToList(); - - // Define method - var method = typeBuilder.DefineMethod( - "Create", - MethodAttributes.Public | MethodAttributes.HideBySig, - arrayType, - new[] { typeof(IResolver) }); + var arrayType = type.MakeArrayType(); - var ilGenerator = method.GetILGenerator(); + var dynamicMethod = new DynamicMethod(string.Empty, arrayType, new[] { holderType, typeof(IResolver) }, true); + var ilGenerator = dynamicMethod.GetILGenerator(); ilGenerator.EmitLdcI4(factories.Length); ilGenerator.Emit(OpCodes.Newarr, type); for (var i = 0; i < factories.Length; i++) { + var field = holderType.GetField($"factory{i}"); + ilGenerator.Emit(OpCodes.Dup); ilGenerator.EmitLdcI4(i); ilGenerator.Emit(OpCodes.Ldarg_0); - ilGenerator.Emit(OpCodes.Ldfld, fields[i]); + ilGenerator.Emit(OpCodes.Ldfld, field); ilGenerator.Emit(OpCodes.Ldarg_1); var invokeMethod = factories[i].GetType().GetMethod("Invoke", new[] { typeof(IResolver) }); ilGenerator.Emit(OpCodes.Call, invokeMethod); @@ -197,22 +117,98 @@ public Func CreateArrayFactory(Type type, Func).MakeGenericType(typeof(IResolver), arrayType); + return (Func)dynamicMethod.CreateDelegate(funcType, holder); + } + + private sealed class HolderBuilder + { + private readonly Dictionary, Type> cache = new Dictionary, Type>(); - // Prepare instance - var instance = Activator.CreateInstance(factoryType); + private AssemblyBuilder assemblyBuilder; - for (var i = 0; i < factories.Length; i++) + private ModuleBuilder moduleBuilder; + + private ModuleBuilder ModuleBuilder { - var fi = factoryType.GetField($"factory{i}"); - fi.SetValue(instance, factories[i]); + get + { + if (moduleBuilder == null) + { + assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly( + new AssemblyName("EmitBuilderAssembly"), + AssemblyBuilderAccess.Run); + moduleBuilder = assemblyBuilder.DefineDynamicModule( + "EmitBuilderModule"); + } + + return moduleBuilder; + } } - // Make delegate - var funcType = typeof(Func<,>).MakeGenericType(typeof(IResolver), arrayType); - // ReSharper disable once AssignNullToNotNullAttribute - return (Func)Delegate.CreateDelegate(funcType, instance, factoryType.GetMethod("Create")); + public object CreateHolder(Func[] factories, Action[] actions) + { + if ((factories.Length == 0) && (actions.Length == 0)) + { + return null; + } + + var key = Tuple.Create(factories.Length, actions.Length); + Type type; + lock (cache) + { + if (!cache.TryGetValue(key, out type)) + { + type = CreateType(factories.Length, actions.Length); + cache[key] = type; + } + } + + var holder = Activator.CreateInstance(type); + + for (var i = 0; i < factories.Length; i++) + { + var field = type.GetField($"factory{i}"); + field.SetValue(holder, factories[i]); + } + + for (var i = 0; i < actions.Length; i++) + { + var field = type.GetField($"action{i}"); + field.SetValue(holder, actions[i]); + } + + return holder; + } + + private Type CreateType(int factoryCount, int actionCount) + { + // Define type + var typeBuilder = ModuleBuilder.DefineType( + $"Holder_{factoryCount}_{actionCount}", + TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.AnsiClass | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit); + + // Define factory fields + for (var i = 0; i < factoryCount; i++) + { + typeBuilder.DefineField( + $"factory{i}", + typeof(Func), + FieldAttributes.Public); + } + + // Define action fields + for (var i = 0; i < actionCount; i++) + { + typeBuilder.DefineField( + $"action{i}", + typeof(Action), + FieldAttributes.Public); + } + + var typeInfo = typeBuilder.CreateTypeInfo(); + return typeInfo.AsType(); + } } } } diff --git a/Smart.Resolver/Smart.Resolver.csproj b/Smart.Resolver/Smart.Resolver.csproj index 72517a0..7d666df 100644 --- a/Smart.Resolver/Smart.Resolver.csproj +++ b/Smart.Resolver/Smart.Resolver.csproj @@ -21,8 +21,4 @@ - - - - \ No newline at end of file