Factory Interface in Simple Injector

后端 未结 1 2034
失恋的感觉
失恋的感觉 2020-12-25 13:43

I\'m a Ninject user that try to learn Simple Injector

One Ninject feture that I often use in my applications is the Factory Interface

With that I can create

相关标签:
1条回答
  • 2020-12-25 14:18

    Simple Injector lacks this a factory interface facility. The idea behind this omission is that when applying Dependency Injection correctly, the need for using factories is minimized, which makes the usefulness of such feature limited.

    In Simple Injector you have to write an implementation yourself, but this is usually trivial. Example:

    private sealed class SimpleInjectorBarFactory : IBarFactory
    {
        private readonly Container container; 
        public SimpleInjectorBarFactory(Container container) => this.container = container;
        public Bar CreateBar() => this.container.GetInstance<Bar>();
    }
    

    This class can be registered like this:

    container.RegisterSingleton<IBarFactory, SimpleInjectorBarFactory>();
    

    Or -if you're lazy- you can register a Func<Bar> to be injected as follows:

    container.RegisterInstance<Func<Bar>>(() => container.GetInstance<Bar>());
    

    Note that since this SimpleInjectorBarFactory implementation depends on the Container instance, it should be part of the Composition Root to prevent using the Container as a Service Locator. By placing the classes inside your Composition Root it becomes merely a piece of infrastructure.

    So the feature is excluded deliberately, but the library can be extended by making use of the ResolveUnregisteredType event:

    using System;
    using System.Linq.Expressions;
    using System.Reflection;
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Remoting.Proxies;
    
    public static class AutomaticFactoryExtensions {
        public static void RegisterFactory<TFactory>(this Container container) {
            if (!typeof(TFactory).IsInterface)
                throw new ArgumentException(typeof(TFactory).Name + " is no interface");
    
            container.ResolveUnregisteredType += (s, e) => {
                if (e.UnregisteredServiceType == typeof(TFactory)) {
                    e.Register(Expression.Constant(
                        value: CreateFactory(typeof(TFactory), container),
                        type: typeof(TFactory)));
                }
            };
        }
    
        private static object CreateFactory(Type factoryType, Container container) {
            var proxy = new AutomaticFactoryProxy(factoryType, container);
            return proxy.GetTransparentProxy();
        }
    
        private sealed class AutomaticFactoryProxy : RealProxy {
            private readonly Type factoryType;
            private readonly Container container;
    
            public AutomaticFactoryProxy(Type factoryType, Container container)
                : base(factoryType) {
                this.factoryType = factoryType;
                this.container = container;
            }
    
            public override IMessage Invoke(IMessage msg) {
                if (msg is IMethodCallMessage) {
                    return this.InvokeFactory(msg as IMethodCallMessage);
                }
    
                return msg;
            }
    
            private IMessage InvokeFactory(IMethodCallMessage msg) {
                if (msg.MethodName == "GetType")
                    return new ReturnMessage(this.factoryType, null, 0, null, msg);
    
                if (msg.MethodName == "ToString")
                    return new ReturnMessage(this.factoryType.Name, null, 0, null, msg);
    
                var method = (MethodInfo)msg.MethodBase;
                object instance = this.container.GetInstance(method.ReturnType);
                return new ReturnMessage(instance, null, 0, null, msg);
            }
        }
    }
    

    Using the extension method above, you can do the registration for the factory in a way very similar to Ninject's registration:

    container.RegisterFactory<IBarFactory>();
    

    That's it.

    0 讨论(0)
提交回复
热议问题