2015-10-22 8 views
11

के साथ जेनरेट किए गए फैक्ट्री को कैसे बनाएं I ऑटोफैक को 'जेनरेटेड' फैक्ट्री के साथ बनाने की कोशिश कर रहा हूं जो वास्तविक समय में निर्भरता को एनम पैरामीटर के आधार पर हल करेगा।ऑटोफैक - पैरामीटर

को देखते हुए निम्नलिखित इंटरफेस/वर्गों:

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. नाम
  2. keyed:

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

    मैं तो विभिन्न विकल्पों के साथ TelnetConnection/SshConnection पंजीकरण के साथ खेलना जारी रखा

  3. मेटाडाटा

मुझे पंजीकरण के सही संयोजन को नहीं मिला जो मुझे एक जेनरेट किए गए फैक्ट्री प्रतिनिधि को परिभाषित करने की अनुमति देगा जो सही कनेक्शन ऑब्जेक्ट (कनेक्शन प्रकार टाइप करने के लिए कनेक्शन कनेक्शन के लिए एसएससी कनेक्शन) और कनेक्शन टाइपनेट के लिए टेलनेट कनेक्शन को वापस कर देगा। enum कुंजी के साथ

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 कार्यान्वयन और रजिस्टर:

उत्तर

11

प्रतिनिधि के बजाय Func<ConnectionType, IConnection> लेने के लिए Engine कक्षा अद्यतन करें। ऑटोफैक 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' का उपयोग करने का बिंदु मैन्युअल रूप से इस बड़े स्विच मामलों को लिखने से बचने के लिए है ताकि इस तर्क को ऑटोफैक द्वारा नियंत्रित किया जा सके। लंबे समय तक यदि इस प्रकार के कई कन्स्ट्रक्टर तर्क हैं तो यह पूरा कोड बहुत जल्दी गन्दा हो सकता है। – nemesv

+0

यदि ओपी 'Func ' के बजाय 'कनेक्शन फ़ैक्टरी' प्रतिनिधि को रखना चाहता है तो निम्नलिखित पंजीकरण कार्य करना चाहिए: 'builder.Register ((सी, पी) => { var type = p.Named ("connectionType"); स्विच (प्रकार) { मामले ConnectionType.Ssh: .... } }) जैसा कि (); 'बिंदु नामित पैरामीटर है नाम '" कनेक्शन टाइप "' प्रतिनिधि घोषणा में पैरामीटर मैच है। – nemesv

+0

मुझे निश्चित रूप से 'IIndex' नहीं दिमाग है लेकिन फिर मैं हमेशा अपने कंटेनर के रूप में ऑटोफैक रखने पर बहुत उत्सुक हूं! : डी –

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 इंटरफ़ेस पहचाना जा सके। – Elie

+0

दूसरे विकल्प के लिए, मुझे यकीन नहीं है कि इसे अभी कैसे काम करना है।'टी' पैरामीटर पहचाना नहीं गया है और इसलिए यह संकलन नहीं कर रहा है। क्या मुझे कुछ याद आ रही है? – Elie

+0

यदि आप अपने डीएल में ऑटोफैक पंजीकृत नहीं करना चाहते हैं तो आपको दूसरे समाधान का उपयोग करने की आवश्यकता है, मुझे नहीं पता कि यह आपके लिए क्यों संकलित नहीं कर रहा है .. त्रुटि संदेश क्या है? आप इसे भी आजमा सकते हैं: 'बिल्डर। रजिस्ट्रार <कनेक्शन फ़ैक्टरी> (सी => { var संदर्भ = c.Resolve (); कनेक्शन फैक्टरी परिणाम = (कनेक्शन टाइप टी) => संदर्भ। >() [टी]; वापसी परिणाम; }); ' – nemesv

संबंधित मुद्दे