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の登録を引き続き試しました。
正しい接続オブジェクト(ConnectionType.Sshの場合はSshConnection、ConnectionType.Telnetの場合はTelnetConnection)を返す、生成されたファクトリデリゲートを定義できる登録の正しい組み合わせが見つかりませんでした。
デリゲートの代わりに_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>())
などです。
パラメータに基づいて実装タイプを選択する必要がある場合は、 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
の実装は同じままにすることができます。