2015-10-22 16 views
11

Bir enum parametresine bağlı olarak bağımlılıkları gerçek zamanlı olarak çözecek bir 'üretilmiş' fabrika Autofac ile oluşturmaya çalışıyorum. Aşağıdaki arayüzler VerilenAutofac - Parametrelerle oluşturulmuş bir fabrika nasıl oluşturulur

/sınıfları:

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

Ben bir parametre alır yöntemi vardır fabrikanın çeşit üretmek için AutoFac kullanmak istiyorum: ConnectionType ve doğru bağlantı döndürür nesne.

aşağıdaki kayıtlar başladı:

  • Named

    1. anahtarlı: Sonra farklı seçeneklerle TelnetConnection/SshConnection kayıtları ile oynamaya devam

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

    2. Meta veriler

    Doğru bağlantı nesnesini (ConnectionType.Ssh için SshConnection ve ConnectionType.Telnet için TelnetConnection) döndüren bir oluşturulmuş fabrika temsilcisini tanımlamamı sağlayan kayıtların doğru birleşimini bulamadım. enum tuşlarıyla IConnection uygulamaları

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

    Ve kayıt: Eğer Paramtre dayalı bir uygulama tipini seçmek gerekiyorsa

  • cevap

    11

    Delegenin yerine Func<ConnectionType, IConnection> almak için Engine sınıfını güncelleştirin. Autofac supports creating delegate factories on the fly via Func<T>. kaydınız olarak

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

    parametreyi yukarı alır ve doğru IConnection örneği döndüren bir lambda kullanın.

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

    kendisi bağımlılık gerekli bağlantı geçerli çağrı bağlamdan çözmek için c parametre üzerinde Resolve diyebiliriz

    . Örneğin, new SshConnection(c.Resolve<IDependency>()).

    +2

    ' IIndex'in kullanılma noktası, bu büyük anahtarlama durumlarını el ile yazmaktan kaçınmaktır, bu nedenle bu mantık Autofac tarafından ele alınabilir. Uzun vadede bu türlerde birden fazla kurucu argümanı varsa, bu kod oldukça hızlı bir şekilde dağınık olabilir. – nemesv

    +0

    OP, 'Func ' yerine 'ConnectionFactory' delegesini tutmak istiyorsa, aşağıdaki kayıt çalışmalıdır:' builder.Register ((c, p) => { var type = p.Named ("ConnectionType"); anahtarı (tip) { durumda ConnectionType.Ssh: .... } }) .as (); 'noktası adı parametredir '' connectionType ''ismi, temsilci bildirgesindeki parametreyi eşleştiriyor. – nemesv

    +0

    Kesinlikle IIndex'i umursamıyorum ama yine de Autofac'i konteyneri olarak tutmaya oldukça hevesliyim! : D –

    5

    Eğer IIndex<T,B> implicit relation type kullanmak gerekir

    builder.RegisterType<Engine>() 
    .   As<IEngine>() 
        .InstancePerDependency(); 
    
    builder.RegisterType<SshConnection>() 
        .Keyed<IConnection>(ConnectionType.Ssh); 
    builder.RegisterType<TelnetConnection>() 
        .Keyed<IConnection>(ConnectionType.Telnet); 
    

    Eğer isterseniz ConnectionFactory numaranızı yanınızda bulundurun ve manuel olarak kullanarak bir IIndex<T,B> kullanın:

    builder.Register<ConnectionFactory>(c => 
    { 
        var context = c.Resolve<IComponentContext>(); 
        return t => context.Resolve<IIndex<ConnectionType, IConnection>>()[t]; 
    }); 
    

    Bu durumda, IConnection türünüzü anahtar olarak kaydetmeniz gerekir, ancak Engine uygulamanız aynı kalabilir.

    +0

    İlk çözümü denedim ve gayet iyi çalışıyor. Benim sorunum, şimdi benim uygulama kodumun Autofac dll'ye bir referansı var, böylece IIndex arayüzü tanınıyor. – Elie

    +0

    İkinci seçenek olarak, nasıl çalışacağından emin değilim.'t' parametresi tanınmadı ve bu nedenle derleme değil. Ben bir şey eksik miyim? – Elie

    +0

    Eğer Autofac'ı dll'inize kaydetmek istemezseniz, ikinci çözümü kullanmalısınız, neden sizin için bir derleme yapmıyor bilmiyorum .. hata iletisi nedir? Ayrıca aşağıdakileri de deneyebilirsiniz: 'builder.Register (c => { var context = c.Resolve (); ConnectionFactory sonucu = (ConnectionType t) => context.Resolve >() [t]; sonuç döndürme; }); ' – nemesv

    İlgili konular