Autofac - 如何使用参数创建生成的工厂

时间:2015-10-22 19:12:07

标签: c# .net autofac

我正在尝试使用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注册:

  1. 命名
  2. 键位
  3. 元数据
  4. 我找不到正确的注册组合,这些注册允许我定义一个生成的工厂委托,它将返回正确的连接对象(ConnectionType.Ssh的SshConnection和ConnectionType.Telnet的TelnetConnection)。

2 个答案:

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