Autofac 不支持将参数传递给父/使用者对象并使这些参数渗透到子对象中。
一般来说我会说要求消费者了解其依赖项接口背后的内容是糟糕的设计。让我解释:
根据您的设计,您有两个界面:IMasterOfPuppets
and IPuppet
。在示例中,您只有一种类型IPuppet
- NamedPuppet
。请记住,拥有接口的目的是将接口与实现分开,您的系统中也可能有这样的:
public class ConfigurablePuppet : IPuppet
{
private string _name;
public ConfigurablePuppet(string name)
{
this._name = ConfigurationManager.AppSettings[name];
}
}
有两件事需要注意。
首先,你有一个不同的实现IPuppet
应该可以代替任何其他IPuppet
当与IMasterOfPuppets
消费者。这IMasterOfPuppets
实施永远不应该知道实施IPuppet
改变了……消耗的东西IMasterOfPuppets
应该进一步删除。
二、两个例子NamedPuppet
和新的ConfigurablePuppet
接受一个同名的字符串参数,但是它意味着与支持实现不同的东西。因此,如果您的消费代码正在执行示例中所示的操作 - 传递一个旨在作为name的事情 - 那么你可能有一个界面设计问题。看:里氏替换原则.
要点是,鉴于IMasterOfPuppets
执行需要一个IPuppet
通过,它不应该关心how the IPuppet
是为了开始或实际支持什么而构建的IPuppet
.一旦它知道,你就打破了接口和实现的分离,这意味着你也可以取消接口并直接传入NamedPuppet
始终是对象。
就传递参数而言,Autofac 确实有参数支持。
推荐且最常见的参数传递类型是注册期间因为那时您可以在容器级别进行设置,并且您没有使用服务位置(即通常被认为是反模式).
如果解析时需要传递参数Autofac 也支持。然而,当在解析过程中传递时,它更像是服务定位器,而不是那么好,因为它再次意味着消费者知道它正在消费什么。
你可以做一些花哨的事情lambda 表达式注册如果您想连接来自已知来源的参数,例如配置。
builder.Register(c => {
var name = ConfigurationManager.AppSettings["name"];
return new NamedPuppet(name);
}).As<IPuppet>();
您还可以使用做一些奇特的事情the Func<T>隐含关系在消费者中:
public class MasterOfPuppets : IMasterOfPuppets
{
IPuppet _puppet;
public MasterOfPuppets(Func<string, IPuppet> puppetFactory)
{
_puppet = puppetFactory("name");
}
}
这样做相当于使用TypedParameter
类型的string
决议期间。但是,正如你所看到的,这来自于直接消费者IPuppet
而不是从所有决议的堆栈中滴下来的东西。
最后,您还可以使用Autofac模块按照您在中看到的方式做一些有趣的横切事情log4net集成模块示例。使用这样的技术允许您通过所有分辨率全局插入特定参数,但它不一定提供在运行时传递参数的能力 - 您必须将参数的源放入模块内。
重点是Autofac 支持参数,但不支持您想要执行的操作。我强烈建议重新设计您做事的方式,这样您实际上就不需要做您正在做的事情,或者您可以通过上述方式之一来解决它。
希望这能让您朝着正确的方向前进。