2015-10-22 13 views
11

私はAutofacを使用して、enumパラメータに基づいてリアルタイムで依存関係を解決する 'generated'ファクトリを作成しようとしています。私は1つのパラメータを受け取るメソッドを持つ工場のいくつかの並べ替えを生成する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(); 
    } 
} 

次のインタフェース/クラスを考えると

CONNECTIONTYPEをし、正しい接続を返します。オブジェクト。

私は、次の登録を開始しました:

  • 名前

    1. を鍵付き:私はその後、別のオプションを持つTelnetConnection/SshConnection登録でプレイし続け

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

    2. メタデータ

    正しい接続オブジェクト(ConnectionType.SshのSshConnectionとConnectionType.TelnetのTelnetConnection)を返す生成されたファクトリデリゲートを定義するための登録の正しい組み合わせが見つかりませんでした。列挙型のキーを使用してIConnection実装を

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

    、レジスタ:あなたはPARAMTERに基づいて実装タイプを選択する必要がある場合は

  • 答えて

    11

    Engineクラスをデリゲートの代わりにFunc<ConnectionType, IConnection>に変更します。 Autofac supports creating delegate factories on the fly 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(); 
        } 
    } 
    

    パラメータをつかみ、正しい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>())です。

    +2

    このIIndexを使用する際のポイントは、この大きなスイッチケースを手作業で書くのを避けることです。このロジックはAutofacで処理することができます。長期的には、この型に複数のコンストラクタ引数がある場合、このコード全体が非常に手早くなる可能性があります。 – nemesv

    +0

    OPが 'Func 'の代わりに 'ConnectionFactory'デリゲートを保持したい場合、次の登録が有効です:' builder.Register ((c、p)=> { var type = ( "connectionTypeに")p.Named; スイッチ(タイプ) {ケースConnectionType.Ssh: ....} }) の.as (); '点が指定されたパラメータでありますname '' connectionType ''はデリゲート宣言のパラメータと一致します。 – nemesv

    +0

    私は確かに 'IIndex'気にしませんが、私はいつも私のコンテナとしてオートファックを保つことに熱心です! :D –

    5

    あなたはIIndex<T,B> implicit relation typeを使用する必要が

    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の実装は同じままです。

    +0

    私は最初の解決策を試しましたが、うまくいきます。私の問題は、今、私のアプリケーションコードは、IIndexインターフェイスが認識されるようにAutofac dllへの参照を持っていることです。 – Elie

    +0

    2番目の選択肢として、私はそれを動作させる方法がまだわかりません。't'パラメータは認識されないため、コンパイルされません。私は何か不足していますか? – Elie

    +0

    あなたのDLLにAutofacを登録したくない場合は、2番目の解決策を使用する必要があります。私はなぜそれがあなたのためにコンパイルされていないのか分かりません。 'builder.Register (c => { varコンテキスト= c.Resolve (); ConnectionFactory result =(ConnectionType t)=> context.Resolve >()[t]; 返品結果; });' – nemesv