Skip to main content
Code Review

Return to Question

replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link

As requested by Heslacher Heslacher, this is a real implementation where I wanted to cache the UserSettings because they will not change over the life span of a request.

As requested by Heslacher, this is a real implementation where I wanted to cache the UserSettings because they will not change over the life span of a request.

As requested by Heslacher, this is a real implementation where I wanted to cache the UserSettings because they will not change over the life span of a request.

added 186 characters in body
Source Link
sQuir3l
  • 209
  • 2
  • 6

Suggested lazy implementation by microsoft Deferring the Resolution of Objects

Suggested lazy implementation by microsoft Deferring the Resolution of Objects

Rollback to Revision 3
Source Link
Heslacher
  • 50.9k
  • 5
  • 83
  • 177
public class LazyTypeFactory
{
 //used to stop the same class being created twice
 private readonly object _lock = new object();
 private readonly Dictionary<Type, Type> _lazyTypes = new Dictionary<Type, Type>();
 private readonly ModuleBuilder _moduleBuilder;
 public LazyTypeFactory(string assembly, string module)
 {
 var an = new AssemblyName(assembly);
 var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
 _moduleBuilder = assemblyBuilder.DefineDynamicModule(module);
 }
 public Type GetOrCreateLazyType<TLazyCreateOrGetLazyType<TLazy, TInterface>(string name = null)
 where TLazy : ILazy<TInterface>, TInterface
 where TInterface : class
 {
 Type result;
 var @interface = typeof (TInterface);
 var @container = typeof (IUnityContainer);
 var @lazy = typeof (TLazy);
 var @func = typeof (Func<IUnityContainer, TInterface>);

 name = name ?? @lazy.Name + "Impl";
 name = @lazy.Namespace + "." + name;
 if ([email protected])
 {
 throw new Exception("Expected TInterface to be a type of interface");
 }

 var @container = typeof (IUnityContainer);
 var @lazy = typeof (TLazy);
 var @func = typeof (Func<IUnityContainer, TInterface>);
 name = @lazy.Namespace + "." + (name ?? @lazy.Name + "Impl"); 

 lock (_lock)
 {
 if (!_lazyTypes.TryGetValueContainsKey(@lazy,))
 out {
  result)) = _lazyTypes[@lazy];
 }
 else
 {
 var typeBuilder = _moduleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Class, null);
 typeBuilder.AddInterfaceImplementation(@lazy);
 //private field for container
 var containerFieldc = typeBuilder.DefineField("_c", @container, FieldAttributes.Public);
 //private field for func
 var funcFieldf = typeBuilder.DefineField("_f", @func, FieldAttributes.Public);
 //private field for func result
 var valueFieldv = typeBuilder.DefineField("_v", @interface, FieldAttributes.Public);
 //constructor with func
 CreateConstructor(typeBuilder, @container, containerFieldc, @func, funcFieldf);
 //private property to get func result
 var propertyBuilder = CreateValueProperty(typeBuilder, @interface, valueFieldv, @container, containerFieldc, @func, funcFieldf);
 
 //interface methods
 //call prop then invok method
 foreach (var iMethod in @interface.GetMethods())
 {
 var mb = CreateOverride(typeBuilder, propertyBuilder, iMethod);
 typeBuilder.DefineMethodOverride(mb, iMethod);
 }
 //property methods
 foreach (var iProperty in @interface.GetProperties())
 {
 var pb = typeBuilder.DefineProperty(iProperty.Name, PropertyAttributes.None, iProperty.PropertyType, Type.EmptyTypes);
 if (iProperty.GetMethod != null)
 {
 var iMethod = iProperty.GetMethod;
 var mb = CreateOverride(typeBuilder, propertyBuilder, iMethod);
 pb.SetGetMethod(mb);
 }
 if (iProperty.SetMethod != null)
 {
 var iMethod = iProperty.SetMethod;
 var mb = CreateOverride(typeBuilder, propertyBuilder, iMethod);
 pb.SetSetMethod(mb);
 }
 }
 _lazyTypes[@lazy] = result = typeBuilder.CreateType();
 }
 }
 return result;
 }
 private static void CreateConstructor(TypeBuilder typeBuilder, Type @container, FieldBuilder containerFieldc, Type @func, FieldBuilder funcFieldf)
 {
 var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { @container, @func });
 constructor.DefineParameter(1, ParameterAttributes.None, "container");
 constructor.DefineParameter(2, ParameterAttributes.None, "func");
 var cIl = constructor.GetILGenerator();
 cIl.Emit(OpCodes.Ldarg_0);
 cIl.Emit(OpCodes.Ldarg_1);
 cIl.Emit(OpCodes.Stfld, containerFieldc);
 cIl.Emit(OpCodes.Ldarg_0);
 cIl.Emit(OpCodes.Ldarg_2);
 cIl.Emit(OpCodes.Stfld, funcFieldf);
 cIl.Emit(OpCodes.Ret);
 }
 private static PropertyBuilder CreateValueProperty(TypeBuilder typeBuilder, Type @interface, FieldBuilder valueFieldv, Type @container, FieldBuilder containerFieldc, Type @func, FieldBuilder funcFieldf)
 {
 var propertyBuilder = typeBuilder.DefineProperty("Value", PropertyAttributes.None, @interface, Type.EmptyTypes);
 var get = typeBuilder.DefineMethod("get_Value", MethodAttributes.Public | MethodAttributes.Virtual, @interface, new Type[0]);
 var getIl = get.GetILGenerator();
 var skip = getIl.DefineLabel();
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldfld, valueFieldv);
 getIl.Emit(OpCodes.Ldnull);
 getIl.Emit(OpCodes.Bne_Un, skip);
 //call _f and set to _v
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldfld, funcFieldf);
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldfld, containerFieldc);
 getIl.Emit(OpCodes.Call, @func.GetMethod("Invoke", new[] { @container }));
 getIl.Emit(OpCodes.Stfld, valueFieldv);
 getIl.MarkLabel(skip);
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldfld, valueFieldv);
 getIl.Emit(OpCodes.Ret);
 propertyBuilder.SetGetMethod(get);
 return propertyBuilder;
 }
 private static MethodBuilder CreateOverride(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, MethodInfo iMethod)
 {
 var mb = typeBuilder.DefineMethod(iMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual,
 iMethod.ReturnType, iMethod.GetParameters().Select(x => x.ParameterType).ToArray());
 var mIL = mb.GetILGenerator();
 mIL.Emit(OpCodes.Ldarg_0);
 mIL.Emit(OpCodes.Call, propertyBuilder.GetMethod);
 for (var i = 0; i < iMethod.GetParameters().Length; i++)
 {
 mIL.Emit(OpCodes.Ldarg, i + 1);
 }
 mIL.Emit(OpCodes.Call, iMethod);
 mIL.Emit(OpCodes.Ret);
 return mb;
 }
}
var factory = new LazyTypeFactory("Assembly.Lazy", "Module.Lazy");
var type = factory.GetOrCreateLazyType<ILazyContractCreateOrGetLazyType<ILazyContract, IContract>();
IUnityContainer container = new UnityContainer();
var factory = new LazyTypeFactory("Assembly.Lazy", "Module.Lazy");
var type = factory.GetOrCreateLazyType<ILazyContractCreateOrGetLazyType<ILazyContract, IContract>();
container.RegisterType<IContract, ContractImplementation>();
var resolve = new Func<IUnityContainer, IContract>(c => c.Resolve<IContract>());
container.RegisterType(typeof(ILazyContract), type, new InjectionConstructor(typeof(IUnityContainer), resolve));
var lazy = container.Resolve<ILazyContract>();
lazy.SomeFunction();

EDIT:
Made edits as suggested by Heslacher

public class LazyTypeFactory
{
 //used to stop the same class being created twice
 private readonly object _lock = new object();
 private readonly Dictionary<Type, Type> _lazyTypes = new Dictionary<Type, Type>();
 private readonly ModuleBuilder _moduleBuilder;
 public LazyTypeFactory(string assembly, string module)
 {
 var an = new AssemblyName(assembly);
 var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
 _moduleBuilder = assemblyBuilder.DefineDynamicModule(module);
 }
 public Type GetOrCreateLazyType<TLazy, TInterface>(string name = null)
 where TLazy : ILazy<TInterface>, TInterface
 where TInterface : class
 {
 Type result;
 var @interface = typeof (TInterface);
 if ([email protected])
 {
 throw new Exception("Expected TInterface to be a type of interface");
 }

 var @container = typeof (IUnityContainer);
 var @lazy = typeof (TLazy);
 var @func = typeof (Func<IUnityContainer, TInterface>);
 name = @lazy.Namespace + "." + (name ?? @lazy.Name + "Impl"); 

 lock (_lock)
 {
 if (!_lazyTypes.TryGetValue(@lazy, out result))
 {
 var typeBuilder = _moduleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Class, null);
 typeBuilder.AddInterfaceImplementation(@lazy);
 //private field for container
 var containerField = typeBuilder.DefineField("_c", @container, FieldAttributes.Public);
 //private field for func
 var funcField = typeBuilder.DefineField("_f", @func, FieldAttributes.Public);
 //private field for func result
 var valueField = typeBuilder.DefineField("_v", @interface, FieldAttributes.Public);
 CreateConstructor(typeBuilder, @container, containerField, @func, funcField);
 //private property to get func result
 var propertyBuilder = CreateValueProperty(typeBuilder, @interface, valueField, @container, containerField, @func, funcField);
 
 //interface methods
 foreach (var iMethod in @interface.GetMethods())
 {
 var mb = CreateOverride(typeBuilder, propertyBuilder, iMethod);
 typeBuilder.DefineMethodOverride(mb, iMethod);
 }
 //property methods
 foreach (var iProperty in @interface.GetProperties())
 {
 var pb = typeBuilder.DefineProperty(iProperty.Name, PropertyAttributes.None, iProperty.PropertyType, Type.EmptyTypes);
 if (iProperty.GetMethod != null)
 {
 var iMethod = iProperty.GetMethod;
 var mb = CreateOverride(typeBuilder, propertyBuilder, iMethod);
 pb.SetGetMethod(mb);
 }
 if (iProperty.SetMethod != null)
 {
 var iMethod = iProperty.SetMethod;
 var mb = CreateOverride(typeBuilder, propertyBuilder, iMethod);
 pb.SetSetMethod(mb);
 }
 }
 _lazyTypes[@lazy] = result = typeBuilder.CreateType();
 }
 }
 return result;
 }
 private static void CreateConstructor(TypeBuilder typeBuilder, Type @container, FieldBuilder containerField, Type @func, FieldBuilder funcField)
 {
 var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { @container, @func });
 constructor.DefineParameter(1, ParameterAttributes.None, "container");
 constructor.DefineParameter(2, ParameterAttributes.None, "func");
 var cIl = constructor.GetILGenerator();
 cIl.Emit(OpCodes.Ldarg_0);
 cIl.Emit(OpCodes.Ldarg_1);
 cIl.Emit(OpCodes.Stfld, containerField);
 cIl.Emit(OpCodes.Ldarg_0);
 cIl.Emit(OpCodes.Ldarg_2);
 cIl.Emit(OpCodes.Stfld, funcField);
 cIl.Emit(OpCodes.Ret);
 }
 private static PropertyBuilder CreateValueProperty(TypeBuilder typeBuilder, Type @interface, FieldBuilder valueField, Type @container, FieldBuilder containerField, Type @func, FieldBuilder funcField)
 {
 var propertyBuilder = typeBuilder.DefineProperty("Value", PropertyAttributes.None, @interface, Type.EmptyTypes);
 var get = typeBuilder.DefineMethod("get_Value", MethodAttributes.Public | MethodAttributes.Virtual, @interface, new Type[0]);
 var getIl = get.GetILGenerator();
 var skip = getIl.DefineLabel();
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldfld, valueField);
 getIl.Emit(OpCodes.Ldnull);
 getIl.Emit(OpCodes.Bne_Un, skip);
 //call _f and set to _v
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldfld, funcField);
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldfld, containerField);
 getIl.Emit(OpCodes.Call, @func.GetMethod("Invoke", new[] { @container }));
 getIl.Emit(OpCodes.Stfld, valueField);
 getIl.MarkLabel(skip);
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldfld, valueField);
 getIl.Emit(OpCodes.Ret);
 propertyBuilder.SetGetMethod(get);
 return propertyBuilder;
 }
 private static MethodBuilder CreateOverride(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, MethodInfo iMethod)
 {
 var mb = typeBuilder.DefineMethod(iMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual,
 iMethod.ReturnType, iMethod.GetParameters().Select(x => x.ParameterType).ToArray());
 var mIL = mb.GetILGenerator();
 mIL.Emit(OpCodes.Ldarg_0);
 mIL.Emit(OpCodes.Call, propertyBuilder.GetMethod);
 for (var i = 0; i < iMethod.GetParameters().Length; i++)
 {
 mIL.Emit(OpCodes.Ldarg, i + 1);
 }
 mIL.Emit(OpCodes.Call, iMethod);
 mIL.Emit(OpCodes.Ret);
 return mb;
 }
}
var factory = new LazyTypeFactory("Assembly.Lazy", "Module.Lazy");
var type = factory.GetOrCreateLazyType<ILazyContract, IContract>();
IUnityContainer container = new UnityContainer();
var factory = new LazyTypeFactory("Assembly.Lazy", "Module.Lazy");
var type = factory.GetOrCreateLazyType<ILazyContract, IContract>();
container.RegisterType<IContract, ContractImplementation>();
var resolve = new Func<IUnityContainer, IContract>(c => c.Resolve<IContract>());
container.RegisterType(typeof(ILazyContract), type, new InjectionConstructor(typeof(IUnityContainer), resolve));
var lazy = container.Resolve<ILazyContract>();
lazy.SomeFunction();

EDIT:
Made edits as suggested by Heslacher

public class LazyTypeFactory
{
 //used to stop the same class being created twice
 private readonly object _lock = new object();
 private readonly Dictionary<Type, Type> _lazyTypes = new Dictionary<Type, Type>();
 private readonly ModuleBuilder _moduleBuilder;
 public LazyTypeFactory(string assembly, string module)
 {
 var an = new AssemblyName(assembly);
 var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
 _moduleBuilder = assemblyBuilder.DefineDynamicModule(module);
 }
 public Type CreateOrGetLazyType<TLazy, TInterface>(string name = null)
 where TLazy : ILazy<TInterface>, TInterface
 where TInterface : class
 {
 Type result;
 var @interface = typeof (TInterface);
 var @container = typeof (IUnityContainer);
 var @lazy = typeof (TLazy);
 var @func = typeof (Func<IUnityContainer, TInterface>);

 name = name ?? @lazy.Name + "Impl";
 name = @lazy.Namespace + "." + name;
 if ([email protected])
 {
 throw new Exception("Expected TInterface to be a type of interface");
 }
 lock (_lock)
 {
 if (_lazyTypes.ContainsKey(@lazy))
  {
  result = _lazyTypes[@lazy];
 }
 else
 {
 var typeBuilder = _moduleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Class, null);
 typeBuilder.AddInterfaceImplementation(@lazy);
 //private field for container
 var c = typeBuilder.DefineField("_c", @container, FieldAttributes.Public);
 //private field for func
 var f = typeBuilder.DefineField("_f", @func, FieldAttributes.Public);
 //private field for func result
 var v = typeBuilder.DefineField("_v", @interface, FieldAttributes.Public);
 //constructor with func
 CreateConstructor(typeBuilder, @container, c, @func, f);
 //private property to get func result
 var propertyBuilder = CreateValueProperty(typeBuilder, @interface, v, @container, c, @func, f);
 
 //interface methods
 //call prop then invok method
 foreach (var iMethod in @interface.GetMethods())
 {
 var mb = CreateOverride(typeBuilder, propertyBuilder, iMethod);
 typeBuilder.DefineMethodOverride(mb, iMethod);
 }
 foreach (var iProperty in @interface.GetProperties())
 {
 var pb = typeBuilder.DefineProperty(iProperty.Name, PropertyAttributes.None, iProperty.PropertyType, Type.EmptyTypes);
 if (iProperty.GetMethod != null)
 {
 var iMethod = iProperty.GetMethod;
 var mb = CreateOverride(typeBuilder, propertyBuilder, iMethod);
 pb.SetGetMethod(mb);
 }
 if (iProperty.SetMethod != null)
 {
 var iMethod = iProperty.SetMethod;
 var mb = CreateOverride(typeBuilder, propertyBuilder, iMethod);
 pb.SetSetMethod(mb);
 }
 }
 _lazyTypes[@lazy] = result = typeBuilder.CreateType();
 }
 }
 return result;
 }
 private static void CreateConstructor(TypeBuilder typeBuilder, Type @container, FieldBuilder c, Type @func, FieldBuilder f)
 {
 var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { @container, @func });
 constructor.DefineParameter(1, ParameterAttributes.None, "container");
 constructor.DefineParameter(2, ParameterAttributes.None, "func");
 var cIl = constructor.GetILGenerator();
 cIl.Emit(OpCodes.Ldarg_0);
 cIl.Emit(OpCodes.Ldarg_1);
 cIl.Emit(OpCodes.Stfld, c);
 cIl.Emit(OpCodes.Ldarg_0);
 cIl.Emit(OpCodes.Ldarg_2);
 cIl.Emit(OpCodes.Stfld, f);
 cIl.Emit(OpCodes.Ret);
 }
 private static PropertyBuilder CreateValueProperty(TypeBuilder typeBuilder, Type @interface, FieldBuilder v, Type @container, FieldBuilder c, Type @func, FieldBuilder f)
 {
 var propertyBuilder = typeBuilder.DefineProperty("Value", PropertyAttributes.None, @interface, Type.EmptyTypes);
 var get = typeBuilder.DefineMethod("get_Value", MethodAttributes.Public | MethodAttributes.Virtual, @interface, new Type[0]);
 var getIl = get.GetILGenerator();
 var skip = getIl.DefineLabel();
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldfld, v);
 getIl.Emit(OpCodes.Ldnull);
 getIl.Emit(OpCodes.Bne_Un, skip);
 //call _f and set to _v
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldfld, f);
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldfld, c);
 getIl.Emit(OpCodes.Call, @func.GetMethod("Invoke", new[] { @container }));
 getIl.Emit(OpCodes.Stfld, v);
 getIl.MarkLabel(skip);
 getIl.Emit(OpCodes.Ldarg_0);
 getIl.Emit(OpCodes.Ldfld, v);
 getIl.Emit(OpCodes.Ret);
 propertyBuilder.SetGetMethod(get);
 return propertyBuilder;
 }
 private static MethodBuilder CreateOverride(TypeBuilder typeBuilder, PropertyBuilder propertyBuilder, MethodInfo iMethod)
 {
 var mb = typeBuilder.DefineMethod(iMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual,
 iMethod.ReturnType, iMethod.GetParameters().Select(x => x.ParameterType).ToArray());
 var mIL = mb.GetILGenerator();
 mIL.Emit(OpCodes.Ldarg_0);
 mIL.Emit(OpCodes.Call, propertyBuilder.GetMethod);
 for (var i = 0; i < iMethod.GetParameters().Length; i++)
 {
 mIL.Emit(OpCodes.Ldarg, i + 1);
 }
 mIL.Emit(OpCodes.Call, iMethod);
 mIL.Emit(OpCodes.Ret);
 return mb;
 }
}
var factory = new LazyTypeFactory("Assembly.Lazy", "Module.Lazy");
var type = factory.CreateOrGetLazyType<ILazyContract, IContract>();
IUnityContainer container = new UnityContainer();
var factory = new LazyTypeFactory("Assembly.Lazy", "Module.Lazy");
var type = factory.CreateOrGetLazyType<ILazyContract, IContract>();
container.RegisterType<IContract, ContractImplementation>();
var resolve = new Func<IUnityContainer, IContract>(c => c.Resolve<IContract>());
container.RegisterType(typeof(ILazyContract), type, new InjectionConstructor(typeof(IUnityContainer), resolve));
var lazy = container.Resolve<ILazyContract>();
lazy.SomeFunction();
added 95 characters in body
Source Link
sQuir3l
  • 209
  • 2
  • 6
Loading
deleted 2 characters in body
Source Link
BCdotWEB
  • 11.4k
  • 2
  • 28
  • 45
Loading
added 1612 characters in body
Source Link
sQuir3l
  • 209
  • 2
  • 6
Loading
Source Link
sQuir3l
  • 209
  • 2
  • 6
Loading
lang-cs

AltStyle によって変換されたページ (->オリジナル) /