autoface -如何创建带有参数的生成工厂

本文关键字:参数 工厂 何创建 创建 autoface | 更新日期: 2023-09-27 18:18:56

我正在尝试使用Autofac创建一个'生成'工厂,该工厂将基于enum参数实时解析依赖项。

给定以下接口/类:

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();
    }
}

我想使用autofacc生成某种类型的工厂,它有一个方法,接收一个参数:ConnectionType并返回正确的连接对象。

我从以下注册开始:

builder.RegisterType<AutoFacConcepts.Engine.Engine>()
    .As<IEngine>()
    .InstancePerDependency();
builder.RegisterType<SshConnection>()
    .As<IConnection>();
builder.RegisterType<TelnetConnection>()
    .As<IConnection>();

然后我用不同的选项继续使用TelnetConnection/SshConnection注册:

    名为<
  1. /gh>
  2. <
  3. 元数据/gh>

我找不到注册的正确组合,这将允许我定义一个生成的工厂委托,它将返回正确的连接对象(SshConnection for ConnectionType)。

autoface -如何创建带有参数的生成工厂

更新Engine类,使其接受Func<ConnectionType, IConnection>而不是委托。Autofac支持通过Func<T>动态创建委托工厂。

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();
    }
}

在您的注册中使用一个lambda来获取参数并返回正确的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>();

如果连接本身需要一个依赖,你可以在c参数上调用Resolve来从当前调用上下文中解决它。例如:new SshConnection(c.Resolve<IDependency>()) .

如果需要根据参数选择实现类型,则需要使用IIndex<T,B>隐式关系类型:

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实现可以保持不变。