将IUnityContainer作为容器解析类型的ctor参数传递

时间:2012-03-30 07:44:29

标签: inversion-of-control unity-container containers

我们计划在项目中使用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 :(得分:0)

如果您想在代码中注册内容,我建议您创建一个注册工厂。然后,您将通过构造函数传递注册工厂,它​​将注册您的对象。这样你就可以从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,则必须手动执行此操作。