我应该将 Unity 容器传递给我的依赖项吗?
所以我有:
应用程序 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);
}
}
}
So I have:
Application A: Requires Class B (different assembly)
Class B: Requires Class C (again, different assembly)
Class C: Uses a container to resolve various objects, but the lifetime of the container (and the objects it resolves) should be controlled by the composition root.
I think I understand how this would work under most circumstances, but in Class C, I need to resolve based on a property of an object that is passed in.
I think what I'm asking is, has the container become a dependency, and as such, how best to get it where it's needed (not sure that I'd really like to pass it through a bunch of constructors - would property injection be the way to go?)
I believe this source is as clean and simple as I can get:
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();
}
}
}
Edit: This is how I made it work with property injection:
I changed 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);
}
}
and updated my Main method in ApplicationA:
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);
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您绝对不想传递容器。您应该查看在这种情况下适用的 Unity 工厂支持。像这样:
然后 ClassC 将有一个 Func 的构造函数参数:
You definitely do not want to be passing around containers. You should look into the Unity factory support which will work in this situation. Something like this:
and then ClassC would have a constructor parameter of Func: