Why I can’t wait to get dynamic in C#
Just wrote again really ugly reflection based code. In such moments I really wish that the ‘dynamic’-type is already here.
I wanted to make this statement, but replace the MyServiceResolvedAtRuntime and ArgumentTypeResolvedAtRuntime with type I only know at runtime.
private static void BuildArgumentProvider(ContainerBuilder builder) { builder.Register<Provider<MyServiceResolvedAtRuntime, ArgumentTypeResolvedAtRuntime>>( ctx => argument => ctx.Resolve<MyServiceResolvedAtRuntime>(new[] { new NamedPropertyParameter("param", argument) })) .As<Provider<MyServiceResolvedAtRuntime, ArgumentTypeResolvedAtRuntime>>(); }
As you may noticed, there are lots of generics and closures involved. So with reflection the whole thing just explodes. Yes, I’m not a .NET-Reflection expert, it’s certainly possible to improve it. But even if you improve it a lot, it still will be ugly. Anyway, I ended with this code:
public AttributeBasedModule{ /** snip **/ private static void BuildArgumentProvider(ConstructorInfo info, Type descriptor, ContainerBuilder builder) { /** snip **/ ParameterInfo info = /** snip **/ var typeToRegister = typeof(Provider<,>).MakeGenericType(new[] { descriptor, argument.ParameterType }); builder.Register<object>(ctx => CreateCreationArgsResolver(typeToRegister,ctx, descriptor,argument)) .As(typeToRegister); } static Delegate CreateCreationArgsResolver(Type typeToRegister,IContext ctx, Type serviceType,ParameterInfo argument) { var ctxKeeper = ContextKeeper.CreateGeneric(ctx, (creationContext, arg) => creationContext.Resolve(serviceType,new Parameter[]{new NamedParameter(argument.Name,arg)}) ,serviceType, argument.ParameterType); return Delegate.CreateDelegate(typeToRegister, ctxKeeper, ReflectionInvokedMethodName); } /// <summary> /// Build the generic version to allow the binding to a particular delegate. /// </summary> static class ContextKeeper { internal static object CreateGeneric(IContext ctx, Func<IContext, object, object> invoker, Type service, Type parameter) { var genericType = typeof (ContextKeeper<,>).MakeGenericType(new[] {service, parameter}); var constructor = genericType.GetConstructor(new[] {typeof (IContext), typeof (Func<IContext, object, object>)}); return constructor.Invoke(new object[] {ctx,invoker}); } } /// <summary> /// Keeping the context for the actual invoker. Represent the context-keeping behavior of closures /// </summary> /// <typeparam name="TService">The service to create</typeparam> /// <typeparam name="TArgument">The constructor-argument for the service</typeparam> class ContextKeeper<TService,TArgument> { private readonly IContext ctx; private readonly Func<IContext, object, object> invoker; public ContextKeeper(IContext ctx, Func<IContext, object, object> invoker) { this.ctx = ctx; this.invoker = invoker; } /// <summary> /// Is invoked by reflection, see <see cref="ReflectionInvokedMethodName"/> /// </summary> /// <param name="arg"></param> /// <returns></returns> public TService Invoke(TArgument arg) { return (TService)invoker.Invoke(ctx, arg); } } }
The .NET 4.0 dynamic-type will make reflection a lot easier. Event more, it will make any calls to dynamic typed stuff like REST-Services, Ruby, JavaScript, XML with no schema, data-stores etc. a pleasure.
- db4o object database
- Small DI-Containers and Autofac