Передача IUnityContainer в качестве аргумента ctor типа разрешенного контейнера - PullRequest
0 голосов
/ 30 марта 2012

Мы планируем использовать Unity в нашем проекте для динамической загрузки объектов / типов, находящихся в разных сборках.Для регистрации типов мы используем файл .config.Я написал небольшой пример приложения, чтобы проверить это, и все работает хорошо.Ниже приведен пример кода:

/* App.config
...
<container name="xyz">
      <register type="IOperations" mapTo="COperations">
        <lifetime type="external" />
      </register>

      <register type="ITest" mapTo="CTest">
        <lifetime type="external" />
      </register>
</container>
...
*/
public class CA
{ }
public class CB
{ }

public interface IMyOperations : IDisposable
{
    void DoSomething(string str);
}
public interface ITest : IDisposable
{
    void DoSomethingElse(string str);
}

class Program
{
    static void Main(string[] args)
    {
        string containerName = "xyz";
        using ( IUnityContainer container = new UnityContainer() )
        {
            UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            section.Configure(container, containerName);

            IMyOperations myOps = container.Resolve<IMyOperations>();
            myOps.DoSomething("Hello");
            myOps.Dispose();

            ITest test = container.Resolve<ITest>();
            test.DoSomethingElse("World!");
            test.Dispose();

        }
    }
}

public class COperations
{
    private IUnityContainer container;
    public COperations(IUnityContainer container)
    {
        this.container = container;
    }

    public void DoSomethingElse(string str)
    {
        // based on runtime values create an instance of class CA or CB and register them with the container
        if (str.Length > 10)
            container.RegisterInstance<CA>("InstanceCA", new CA());
        else
            container.RegisterInstance<CB>("InstanceCB", new CB());
    }
    public void Dispose()
    { }
}


public class CTest
{
    private IUnityContainer container;
    public CTest(IUnityContainer container)
    {
        this.container = container;
    }

    public void DoSomethingElse(string str)
    {
        // based on runtime values get the registered instance of class CA or CB
        if (str.Length > 100)
            container.Resolve<CA>("InstanceCA");
        else
            container.Resolve<CB>("InstanceCB");
    }
    public void Dispose()
    { }
}

Я также создаю новые объекты (класса CA и CB в приведенном выше коде) в типе контейнера с разрешением и регистрирую их в контейнере с помощью ResisterInstance ().Для этого я изменяю сигнатуру ctor моего контейнера-типа-типа выглядит следующим образом:

public COperations (контейнер IUnityContainer)

Я не уверен, что это правильноподход.Есть ли лучший способ использовать контейнер для регистрации экземпляра из объекта типа контейнера?Я пытаюсь разделить несколько объектов друг с другом, которые я могу знать только во время выполнения.Кроме того, это делает мои компоненты встроенными в Unity и бесполезным, если мы решим перейти на другой контейнер в более поздний момент времени.

1 Ответ

0 голосов
/ 30 марта 2012

Я бы предложил создать фабрику регистрации, если вы хотите зарегистрировать вещи в коде. Затем вы будете передавать фабрику регистрации через конструктор, и она будет регистрировать ваши объекты. Это позволит вам отделиться от Unity.

Итак:

public interface IRegistrationFactory
{
    void RegisterInstance<TI,TO>();
    void RegisterType<TI,TO>();
    void RegisterInstance<TI,TO>(string name, TO objectToRegister);
}

public class COperations
{
    private IRegistrationFactory _factory;
    public COperations(IRegistrationFactory factory)
    {
        _factory= factory;
    }

    public void DoSomethingElse(string str)
    {
        // based on runtime values create an instance of class CA or CB and register them with the container
        if (str.Length > 10)
            _factory.RegisterInstance<CA,CA>("InstanceCA", new CA());
        else
            _factory.RegisterInstance<CB,CB>("InstanceCB", new CB());
    }

вам, очевидно, нужно реализовать IRegistrationFactory. Все это будет класс, который принимает IUnityContainer в своем конструкторе, а затем реализует интерфейс.

Если вы решили перейти с Unity на другой контейнер DI, все, что вам нужно сделать, это настроить IRegistrationFactory для обработки нового контейнера DI.

Кроме того, если вы регистрируете экземпляры, вы можете сделать это следующим образом:

_container.RegisterType (new ContainerControlledLifetimeManager ());

это всегда будет возвращать один и тот же экземпляр объекта, поэтому он похож на RegisterInstance. Преимущество этого подхода в том, что Unity разрешит любую из зависимостей CA для вас, тогда как если вы используете RegisterInstance, вам придется сделать это вручную.

...