J'essaie de créer avec Autofac une usine "générée" qui résoudra les dépendances en temps réel en fonction d'un paramètre enum.
Étant donné les interfaces/classes suivantes :
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();
}
}
Je voudrais utiliser Autofac pour générer une sorte d'usine qui a une méthode qui reçoit un paramètre: ConnectionType et renvoie l'objet de connexion correct.
J'ai commencé avec les enregistrements suivants:
builder.RegisterType<AutoFacConcepts.Engine.Engine>()
.As<IEngine>()
.InstancePerDependency();
builder.RegisterType<SshConnection>()
.As<IConnection>();
builder.RegisterType<TelnetConnection>()
.As<IConnection>();
J'ai ensuite continué à jouer avec les enregistrements TelnetConnection/SshConnection avec différentes options:
Je n'ai pas trouvé la combinaison correcte des enregistrements qui me permettra de définir un délégué d'usine généré qui renverra l'objet de connexion correct (SshConnection pour ConnectionType.Ssh et TelnetConnection pour ConnectionType.Telnet).
Mettez à jour la classe Engine
pour prendre un Func<ConnectionType, IConnection>
À la place du délégué. Autofac prend en charge la création d'usines de délégués à la volée via 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();
}
}
Dans votre enregistrement, utilisez un lambda qui récupère le paramètre et renvoie l'instance IConnection
correcte.
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>();
Si la connexion elle-même nécessite une dépendance, vous pouvez appeler Resolve
sur le paramètre c
pour la résoudre à partir du contexte d'appel actuel. Par exemple, new SshConnection(c.Resolve<IDependency>())
.
Si vous devez sélectionner un type d'implémentation basé sur un paramètre, vous devez utiliser IIndex<T,B>
type de relation implicite :
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();
}
}
Et enregistrez vos implémentations IConnection
avec les clés enum:
builder.RegisterType<Engine>()
. As<IEngine>()
.InstancePerDependency();
builder.RegisterType<SshConnection>()
.Keyed<IConnection>(ConnectionType.Ssh);
builder.RegisterType<TelnetConnection>()
.Keyed<IConnection>(ConnectionType.Telnet);
Si vous souhaitez conserver votre ConnectionFactory
, vous pouvez l'enregistrer manuellement pour utiliser un IIndex<T,B>
en interne avec:
builder.Register<ConnectionFactory>(c =>
{
var context = c.Resolve<IComponentContext>();
return t => context.Resolve<IIndex<ConnectionType, IConnection>>()[t];
});
Dans ce cas, vous devez toujours enregistrer vos types IConnection
en tant que clés, mais votre implémentation Engine
peut rester la même.