web-dev-qa-db-ja.com

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を1つ受け取り、正しい接続オブジェクトを返すメソッドを持つファクトリーを生成したいと思います。

以下の登録から始めました:

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

builder.RegisterType<SshConnection>()
    .As<IConnection>();
builder.RegisterType<TelnetConnection>()
    .As<IConnection>();

その後、さまざまなオプションを使用してTelnetConnection/SshConnectionの登録を引き続き試しました。

  1. 名前付き
  2. キー付き
  3. メタデータ

正しい接続オブジェクト(ConnectionType.Sshの場合はSshConnection、ConnectionType.Telnetの場合はTelnetConnection)を返す、生成されたファクトリデリゲートを定義できる登録の正しい組み合わせが見つかりませんでした。

18
Elie

デリゲートの代わりに_Func<ConnectionType, IConnection>_を取るようにEngineクラスを更新します。 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();
    }
}
_

登録では、パラメーターを取得して正しい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を呼び出して、現在の呼び出しコンテキストから解決できます。たとえば、new SshConnection(c.Resolve<IDependency>())などです。

20

パラメータに基づいて実装タイプを選択する必要がある場合は、 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の実装は同じままにすることができます。

9
nemesv