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.

Tagged on: ,

Leave a Reply

Your email address will not be published. Required fields are marked *