IoC、工厂和构造函数参数
我是一个在 IoC 和 DI 方面苦苦挣扎的初学者。我希望能够使用 autofac (或任何其他合适的 .NET IoC 工具)动态解析连接和连接工厂。
一种场景可能是将连接实现更改为另一种具有更多跟踪功能的连接实现。
当我将 DI 和 IoC 应用于下面的代码时,我在构造函数等中得到一堆命名参数。连接工厂返回一个具有唯一端口的新连接(愚蠢的例子,只是为了表明我需要在工厂中保留某种状态)
我想我可以对 IP 和端口范围使用属性注入,但这样,我就不能保证连接有一个 IP或端口,这是构造函数的要点。 此外,命名参数也使我依赖于参数的名称。
非常感谢想法、模式、IoC 指针!
更新:
更具体:如何将连接类更改为可注入?我应该进行财产注入吗?或者我可以采取任何技巧来使用构造函数参数进行更类型安全的解析?
public interface IConnection {
void Open();
void Close();
string Execute(string command);
}
public interface IConnectionFactory {
IConnection CreateConnection();
}
public class Connection : IConnection {
...
public Connection(String ip, int port) {
_ip = ip;
_port = port;
}
public string Execute() {}
public void Open() {}
public void Close() {}
}
public class ConnectionFactory : IConnectionFactory {
//How would I resolve this?
public ConnectionFactory(string ip, int fromPort) {
...
}
public IConnection CreateConnection() {
//How would I resolve this?
return new Connection(ip, fromPort++);
}
}
现在,用法:
//Register
builder.RegisterType<Connection>().As<IConnection>();
builder.RegisterType<ConnectionFactory>().As<IConnectionFactory>().SingleInstance();
...
var connection = container.Resolve<IConnectionFactory>(
new NamedParameter("ip", "127.0.0.1"),
new NamedParameter("fromPort", 80).CreateConnection());
I'm a beginner struggling with IoC and DI. I'd like to be able to resolve the connection and connection factory dynamically using autofac (or any other suitable .NET IoC tool).
A scenario could be changing the connection implementation to another one with more facilities for tracing etc.
When I apply DI and IoC to the code below, I get a mess of namedParameter in constructors etc. The connection factory returns a new connection with a unique port (silly example, just to show I need to keep some sort of state in the factory)
I figure I could use property injection for the IP and port range, but that way, I wouldn't be guaranteed that the connections would have an IP or port, which is the point of a constructor.
Also, the named parameters make me dependent on the names of the arguments as well.
Ideas, patterns, IoC pointers are much appreciated!
Update:
More specific: How could I change the connection class to be injectable? Should I go with property injection? Or any tricks I could do get a more type-safe resolving with constructor arguments?
public interface IConnection {
void Open();
void Close();
string Execute(string command);
}
public interface IConnectionFactory {
IConnection CreateConnection();
}
public class Connection : IConnection {
...
public Connection(String ip, int port) {
_ip = ip;
_port = port;
}
public string Execute() {}
public void Open() {}
public void Close() {}
}
public class ConnectionFactory : IConnectionFactory {
//How would I resolve this?
public ConnectionFactory(string ip, int fromPort) {
...
}
public IConnection CreateConnection() {
//How would I resolve this?
return new Connection(ip, fromPort++);
}
}
Now, the usage:
//Register
builder.RegisterType<Connection>().As<IConnection>();
builder.RegisterType<ConnectionFactory>().As<IConnectionFactory>().SingleInstance();
...
var connection = container.Resolve<IConnectionFactory>(
new NamedParameter("ip", "127.0.0.1"),
new NamedParameter("fromPort", 80).CreateConnection());
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在解析时传递构造函数参数的另一种方法是在注册函数中对这些参数进行编码:
Autofac 将在需要创建连接工厂实例时使用该函数。
由于我们将
ConnectionFactory
配置为SingleInstance
,它将在依赖于IConnectionFactory
的所有组件之间共享。这意味着ConnectionFactory
需要在调用CreateConnection
之间保持自己的状态:如果您有一个一次性的
ConnectionFactory
,比如说,它使用不同的IP,您可以使用命名注册:当您希望组件使用该特定工厂而不是默认工厂时,您可以使用
ResolveNamed
方法:这是一种以多种方式配置类型并在特定位置使用它们的便捷技术。
An alternative to passing the constructor arguments at resolve-time is to encode those arguments in the registration function:
Autofac will use that function whenever it needs to create the connection factory instance.
Since we configured
ConnectionFactory
asSingleInstance
, it will be shared amongst all components which depend onIConnectionFactory
. This meansConnectionFactory
needs to keep its own state between calls toCreateConnection
:If you have a one-off
ConnectionFactory
which, say, uses a different IP, you can use a named registration:When you want a component to use that particular factory instead of the default one, you can use the
ResolveNamed
method:This is a handy technique to configure a type in multiple ways and use them in specific places.
我对 Autofac 没有经验,但我在 Unity 中解决了一个非常类似的问题。这是一个片段:
当我配置容器时,我会执行类似的操作(甚至可以在配置文件中完成):
稍后,我可以通过以下方式构建连接:
或指定依赖属性:
或作为可注入参数构造函数注入:
我留下 PerThreadLifetimeManager 来指出我让 IoC 处理确保没有两个线程共享连接。
尽管与问题中的示例的差异很细微,但它确实从每个实例化中删除了参数,这允许您将其作为依赖项属性或作为注入构造函数的一部分。
希望有帮助。
I am not experienced with Autofac but I solved a very similar problem in Unity. Here's a snippet:
When I configure my container I do something like this (this can even be done in the config file):
Later on, I can build the connections by just saying:
or specifying a dependency property:
or as an injectable parameter for constructor injection:
I left the PerThreadLifetimeManager to point out that I let the IoC deal with ensuring that no two threads are sharing a connection.
Although the difference with your sample in the question is subtle, it does remove the parameters from each instantiation which allows you to have it as a dependency property or as part of an injection constructor.
Hope that helps.
一种灵活的方法可能是创建一个“AppConfigConnectionFactory”(或 WebConfig、DBConfig 等)并通过配置外部化这些属性。我从来没有觉得直接从 DI 框架加载配置数据是正确的。
A flexible approach might be to create an "AppConfigConnectionFactory" (or WebConfig, DBConfig, etc...) and externalize these properties via configuration. I've never felt right loading configuration data straight from the DI framework.