我正在尝试使用Autofac创建一个'生成'工厂,它将根据枚举参数实时解析依赖关系。
给定以下接口/类 :
public delegate IConnection ConnectionFactory(ConnectionType connectionType);
public enum ConnectionType
{
Telnet,
Ssh
}
public interface IConnection
{
bool Open();
}
public class SshConnection : ConnectionBase, IConnection
{
public bool Open()
{
return false;
}
}
public class TelnetConnection : ConnectionBase, IConnection
{
public bool Open()
{
return true;
}
}
public interface IEngine
{
string Process(ConnectionType connectionType);
}
public class Engine : IEngine
{
private ConnectionFactory _connectionFactory;
public Engine(ConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
public string Process(ConnectionType connectionType)
{
var connection = _connectionFactory(connectionType);
return connection.Open().ToString();
}
}
我想使用Autofac生成某种工厂,该工厂有一个接收一个参数的方法:ConnectionType并返回正确的连接对象。
我从以下注册开始:
builder.RegisterType<AutoFacConcepts.Engine.Engine>()
.As<IEngine>()
.InstancePerDependency();
builder.RegisterType<SshConnection>()
.As<IConnection>();
builder.RegisterType<TelnetConnection>()
.As<IConnection>();
然后我继续使用不同选项的TelnetConnection / SshConnection注册:
我找不到正确的注册组合,这些注册允许我定义一个生成的工厂委托,它将返回正确的连接对象(ConnectionType.Ssh的SshConnection和ConnectionType.Telnet的TelnetConnection)。
答案 0 :(得分:15)
更新JButton
课程以取代Engine
而不是代理人。 Autofac supports creating delegate factories on the fly via Func<T>
。
Func<ConnectionType, IConnection>
在您的注册中使用lambda来抓取参数并返回正确的public class Engine : IEngine
{
private Func<ConnectionType, IConnection> _connectionFactory;
public Engine(Func<ConnectionType, IConnection> connectionFactory)
{
_connectionFactory = connectionFactory;
}
public string Process(ConnectionType connectionType)
{
var connection = _connectionFactory(connectionType);
return connection.Open().ToString();
}
}
实例。
IConnection
如果连接本身需要依赖关系,则可以在builder.Register<IConnection>((c, p) =>
{
var type = p.TypedAs<ConnectionType>();
switch (type)
{
case ConnectionType.Ssh:
return new SshConnection();
case ConnectionType.Telnet:
return new TelnetConnection();
default:
throw new ArgumentException("Invalid connection type");
}
})
.As<IConnection>();
参数上调用Resolve
以从当前调用上下文中解析它。例如,c
。
答案 1 :(得分:8)
如果您需要根据参数选择实施类型,则需要使用IIndex<T,B>
implicit relation type:
public class Engine : IEngine
{
private IIndex<ConnectionType, IConnection> _connectionFactory;
public Engine(IIndex<ConnectionType, IConnection> connectionFactory)
{
_connectionFactory = connectionFactory;
}
public string Process(ConnectionType connectionType)
{
var connection = _connectionFactory[connectionType];
return connection.Open().ToString();
}
}
使用枚举键注册您的IConnection
实现:
builder.RegisterType<Engine>()
. As<IEngine>()
.InstancePerDependency();
builder.RegisterType<SshConnection>()
.Keyed<IConnection>(ConnectionType.Ssh);
builder.RegisterType<TelnetConnection>()
.Keyed<IConnection>(ConnectionType.Telnet);
如果您想保留ConnectionFactory
,可以手动注册,以便在内部使用IIndex<T,B>
:
builder.Register<ConnectionFactory>(c =>
{
var context = c.Resolve<IComponentContext>();
return t => context.Resolve<IIndex<ConnectionType, IConnection>>()[t];
});
在这种情况下,您仍然需要将IConnection
类型注册为键控,但您的Engine
实施可以保持不变。