Подтвердить что ты не робот

Factory Интерфейс в простом инжекторе

Я пользователь Ninject, который пытается изучить Simple Injector

Один фрейм Ninject, который я часто использую в своих приложениях, это Factory Интерфейс

С этим я могу создать интерфейс вроде этого:

public interface IBarFactory
{
   Bar CreateBar();
}

И зарегистрируйте его так:

kernel.Bind<IBarFactory>().ToFactory();

Тогда я просто могу использовать IBarFactory, и не нужно создавать реализацию IBarFactory

Теперь я пытаюсь найти что-нибудь подобное в Simple njector и нашел этот. Но с этим помощником я должен реализовать интерфейс factory (больше кода). И как мне сделать, если объект Bar нужен ссылка на другой объект?

4b9b3361

Ответ 1

Простой инжектор не имеет этого интерфейса factory. Идея заключается в том, что при правильном применении Injection Dependency необходимость использования заводов минимизируется, что делает полезность такой функции ограниченной.

В Simple Injector вам нужно написать реализацию самостоятельно, но это обычно тривиально. Пример:

private sealed class SimpleInjectorBarFactory : IBarFactory {
    private readonly Container container; 

    public SimpleInjectorBarFactory(Container container) {
        this.container = container;
    }

    public Bar CreateBar() {
        return this.container.GetInstance<Bar>();
    }
}

Этот класс можно зарегистрировать следующим образом:

container.RegisterSingleton<IBarFactory, SimpleInjectorBarFactory>();

Или, если вы ленивы, вы можете зарегистрировать Func<Bar> для инъекции следующим образом:

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

Обратите внимание, что поскольку эта реализация SimpleInjectorBarFactory зависит от экземпляра Container, она должна быть частью Root of Composition, чтобы предотвратить использование Контейнер как Сервис-локатор. Помещая классы внутри вашего корня композиции, он становится просто частью инфраструктуры.

Таким образом, функция исключается специально, но библиотека может быть продлена достаточно легко, чтобы это можно было с ограниченным количеством кода:

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);
        }
    }
}

Используя вышеописанный метод расширения, вы можете сделать регистрацию для factory способом, очень похожим на регистрацию Ninject:

container.RegisterFactory<IBarFactory>();

Что это.