我应该将Unity容器传递给我的依赖项吗?

时间:2011-01-26 16:18:00

标签: c# dependency-injection unity-container

所以我有:

应用程序A:需要B类(不同的程序集)

B类:需要C级(同样,不同的装配)

C类:使用容器来解析各种对象,但是容器的生命周期(以及它解析的对象)应该由组合根控制。

我想我理解这在大多数情况下是如何工作的,但是在C类中,我需要根据传入的对象的属性来解决。

我认为我要问的是,容器是否已成为一种依赖关系,因此,如何最好地将它放在需要的地方(不确定我是否真的希望将它传递给一堆施工人员 - 物业注入是否可行?)

我相信这个来源尽可能干净简洁:

namespace InjectionTest
{
    using System;
    using Microsoft.Practices.Unity;

    public class ApplicationA
    {
        static void Main(string[] args)
        {
            using (IUnityContainer container = new UnityContainer())
            {
                // Normally I'd use this, but for clarity in the example, I'm doing it in code.
                //container.LoadConfiguration(); 
                container.RegisterType<IClassB, ClassB>();
                container.RegisterType<IClassC, ClassC>();
                container.RegisterType<IFooBuilder, FrobBuilder>("frob");
                container.RegisterType<IFooBuilder, WidgetBuilder>("widget");
                IClassB machine = container.Resolve<IClassB>();
                InitialObject bar = new InitialObject() { Name = "widget" };
                machine.doSomethingWithBar(bar);
                bar = new InitialObject() { Name = "frob" };
                machine.doSomethingWithBar(bar);
            }
        }
    }

    public class ClassB : IClassB
    {
        IClassC classC { get; private set; }

        public ClassB(IClassC classc)
        {
            this.classC = classc;
        }

        public void doSomethingWithBar(InitialObject bar)
        {
            var foo = this.classC.BuildMyFoo(bar);
            /*
             * Do something else with foo & bar
             * */
        }

    }

    public interface IClassB
    {
        void doSomethingWithBar(InitialObject bar);
    }

    public class ClassC : IClassC
    {
        public ResultObject BuildMyFoo(InitialObject bar)
        {
            IFooBuilder builder = null;
            //How best do I get my container here?
            //IFooBuilder builder = container.Resolve<IFooBuilder>(bar.Name);
            return builder.build(bar);
        }
    }

    public interface IClassC
    {
        ResultObject BuildMyFoo(InitialObject bar);
    }

    public class InitialObject
    {
        public string Name { get; set; }
    }

    public class ResultObject
    {
        public string SomeOtherData { get; set; }
    }

    public interface IFooBuilder
    {
        ResultObject build(InitialObject bar);
    }

    public class FrobBuilder : IFooBuilder
    {
        public ResultObject build(InitialObject bar)
        {
            throw new NotImplementedException();
        }
    }

    public class WidgetBuilder : IFooBuilder
    {
        public ResultObject build(InitialObject bar)
        {
            throw new NotImplementedException();
        }
    }
}

编辑:这就是我使用属性注入的方式:

我改变了ClassC:

public class ClassC : IClassC
{
    [Dependency]
    public IUnityContainer Container { get; set; }

    public ResultObject BuildMyFoo(InitialObject bar)
    {
        IFooBuilder builder = null;
        //How best do I get my container here?
        builder = Container.Resolve<IFooBuilder>(bar.Name);
        return builder.build(bar);
    }
}

并在ApplicationA中更新了我的Main方法:

    public void Main()
    {
        using (IUnityContainer container = new UnityContainer())
        {
            // Normally I'd use this, but for clarity in the example, I'm doing it in code.
            //container.LoadConfiguration(); 
            container.RegisterType<IClassB, ClassB>();
            container.RegisterType<IClassC, ClassC>();
            container.RegisterType<IFooBuilder, FrobBuilder>("frob");
            container.RegisterType<IFooBuilder, WidgetBuilder>("widget");
            using (IUnityContainer child = container.CreateChildContainer())
            {
                container.RegisterInstance<IUnityContainer>(child);
                IClassB machine = container.Resolve<IClassB>();
                InitialObject bar = new InitialObject() { Name = "widget" };
                machine.doSomethingWithBar(bar);
                bar = new InitialObject() { Name = "frob" };
                machine.doSomethingWithBar(bar);
            }
        }
    }

1 个答案:

答案 0 :(得分:8)

你绝对不想传递容器。您应该查看Unity工厂支持,它将在这种情况下工作。像这样:

container.RegisterType<IFooBuilder, FrobBuilder>("Frob")
         .RegisterType<IFooBuilder, WidgetBuilder>("Widget")
         .RegisterType<Func<string, IFooBuilder>>(new InjectionFactory(c => new Func<string, IFooBuilder>(barName => c.Resolve<IFooBuilder>(barName))))

然后ClassC的构造函数参数为Func:

public class ClassC : IClassC
{
  private readonly Func<string, IFooBuilder> _builderFactory;

  public ClassC(Func<string, IFooBuilder> builderFactory)
  {
    _builderFactory = builderFactory;
  }

  public ResultObject BuildMyFoo(InitialObject bar)
  {
    IFooBuilder builder = _builderFactory(bar.Name);
    return builder.build(bar);
  }
}