2016-02-09 12 views
8

मेरे पास कई कक्षाएं हैं जो ILogger प्रकार की निर्भरता लेती हैं। ILogger के कार्यान्वयन प्रकार है जिसके लिए वह लकड़हारा है पता करने के लिए की जरूरत है, यानी Foo के लिए ILoggernew Logger(typeof(Foo)) हो जाएगा, Bar के लिए यह new Logger(typeof(Bar)) हो जाएगा, आदिनिर्भरता को हल करने के लिए हल किए जा रहे प्रकार का उपयोग कैसे करें

मैं उचित लकड़हारा एकता द्वारा स्वचालित रूप से इंजेक्ट किया जा चाहते हैं ; दूसरे शब्दों में, जब मैं container.Resolve<Foo>() पर कॉल करता हूं, तो मुझे Foo उदाहरण में इंजेक्शन देने के लिए new Logger(typeof(Foo)) चाहिए।

मैं इसे एकता में कैसे स्थापित कर सकता हूं? निर्भरता के प्रकार को हल करने का कोई तरीका है?

(मेरा असली कोड में, मैं वास्तव में एक Create विधि है, जो भी एक पैरामीटर के रूप में एक प्रकार लेता है। इसलिए मैं सिर्फ अपनी कक्षाओं के लिए कारखाने से निकल सकती है एक ILoggerFactory है, और वे Create खुद को कॉल प्राप्त करने के लिए होगा

interface ILogger 
{ 
    ... 
} 

class Logger : ILogger 
{ 
    private readonly Type _type; 
    public Logger(Type type) 
    { 
     _type = type; 
    } 
    ... 
} 

class Foo 
{ 
    private readonly ILogger _logger; 
    public Foo(ILogger logger) // here I want a Logger with its type set to Foo 
    { 
     _logger = logger; 
    } 
} 

: उचित लकड़हारा, लेकिन ऐसा नहीं मैं प्राप्त करना चाहते हैं)


कुछ कोड के रूप में के रूप में सुंदर बातें स्पष्ट करने का तरीका बताया

यह related question बिल्कुल दिखाता है कि मैं क्या करने की कोशिश कर रहा हूं, और स्वीकार्य उत्तर बिल्कुल वही चीज़ है जो मैं ढूंढ रहा हूं ... लेकिन यह एन इंजेक्ट के लिए है, एकता नहीं।

+0

विल' लकड़हारा = नए लॉगर (GetType()):

और यकीन है कि यह काम कर रहा है कुछ कोड (मैं लकड़हारा करने के लिए एक प्रकार संपत्ति सिर्फ सत्यापित करने के लिए यह ठीक से सेट है जोड़ा) आप?GetType() हमेशा सबसे व्युत्पन्न कक्षा प्रकार देता है। मैं हर जगह टाइपऑफ (कक्षा) पास करता था लेकिन GetType() विधि बिल्कुल वही करता है जो मुझे चाहिए। – Quantic

+0

@Quantic, नहीं, यह नहीं होगा। मेरी कक्षाएं 'ILogger' के कार्यान्वयन को नहीं जानती हैं (जो निर्भरता इंजेक्शन का पूरा बिंदु है), इसलिए वे' लॉगर 'का उदाहरण नहीं बना सकते हैं। मुझे लगता है कि आपने मेरे प्रश्न को गलत समझा, लेकिन कोशिश करने के लिए धन्यवाद;) –

+1

मुझे लगा कि मैंने आपकी प्रतिष्ठा और बैज हेह को देखने के बाद गलती की थी। मैं अपने कोने पर वापस जाऊंगा;) – Quantic

उत्तर

4

यहां एक कंटेनर एक्सटेंशन है जो लॉगर कन्स्ट्रक्टर के प्रकार पैरामीटर को उस प्रकार से सेट करेगा जो इलोगर इंजेक्शन में लगाया जा रहा है।

क्षणिक IBuilderContext.Policies का उपयोग उस प्रकार को संग्रहीत करने के लिए किया जाता है जिसे ILogger इंजेक्शन दिया जा रहा है।

शायद यह और अधिक जटिल की तुलना में यह करने की जरूरत है, लेकिन इस

public class LoggerExtension : UnityContainerExtension 
{ 
    public static NamedTypeBuildKey LoggerBuildKey = new NamedTypeBuildKey<Logger>(); 

    protected override void Initialize() 
    { 
     Context.Strategies.Add(new LoggerTrackingPolicy(), UnityBuildStage.TypeMapping); 
     Context.Strategies.Add(new LoggerBuildUpStrategy(), UnityBuildStage.PreCreation); 
    } 
} 

public class LoggerTrackingPolicy : BuilderStrategy 
{ 
    public LoggerTrackingPolicy() 
    { 
    } 

    public override void PreBuildUp(IBuilderContext context) 
    { 
     if (context.BuildKey.Type != typeof(Logger)) 
     { 
      var loggerPolicy = context.Policies.Get<ILoggerPolicy>(LoggerExtension.LoggerBuildKey); 
      if (loggerPolicy == null) 
      { 
       loggerPolicy = new LoggerPolicy(); 
       context.Policies.Set<ILoggerPolicy>(loggerPolicy, LoggerExtension.LoggerBuildKey); 
      } 

      loggerPolicy.Push(context.BuildKey.Type); 
     } 
    } 
} 

public class LoggerBuildUpStrategy : BuilderStrategy 
{ 
    public LoggerBuildUpStrategy() 
    { 
    } 

    public override void PreBuildUp(IBuilderContext context) 
    { 
     if (context.BuildKey.Type == typeof(Logger)) 
     { 
      var policy = context.Policies.Get<ILoggerPolicy>(LoggerExtension.LoggerBuildKey); 
      Type type = policy.Peek(); 
      if (type != null) 
      { 
       context.AddResolverOverrides(new ParameterOverride("type", new InjectionParameter(typeof(Type), type))); 
      } 
     } 
    } 

    public override void PostBuildUp(IBuilderContext context) 
    { 
     if (context.BuildKey.Type != typeof(Logger)) 
     { 
      var policy = context.Policies.Get<ILoggerPolicy>(LoggerExtension.LoggerBuildKey); 
      policy.Pop(); 
     } 
    } 
} 

public interface ILoggerPolicy : IBuilderPolicy 
{ 
    void Push(Type type); 
    Type Pop(); 
    Type Peek(); 
} 

public class LoggerPolicy : ILoggerPolicy 
{ 
    private Stack<Type> types = new Stack<Type>(); 

    public void Push(Type type) 
    { 
     types.Push(type); 
    } 

    public Type Peek() 
    { 
     if (types.Count > 0) 
     { 
      return types.Peek(); 
     } 

     return null; 
    } 

    public Type Pop() 
    { 
     if (types.Count > 0) 
     { 
      return types.Pop(); 
     } 

     return null; 
    } 
} 

काम करने के लिए यह कैसे काम करता है लगता है है: जब एक प्रकार है कि एक लॉगर TypeMapping चरण के दौरान, तो हल किया जा करने की कोशिश कर रहा है (किसी भी सृजन से पहले), प्रकार को एक ढेर पर धक्का दिया जाता है। बाद में, सृजन से पहले, यदि प्रकार लॉगर होता है तो उस प्रकार को इंजेक्शन दिया जा रहा है जिसे स्टैक से देखा जाता है और उस प्रकार को रिज़ॉलर ओवरराइड के रूप में उपयोग किया जाता है। सृजन के बाद, यदि प्रकार लॉगर नहीं है, तो यह ढेर से पॉप किया गया है। `के लिए काम करते;

class Program 
{ 
    static void Main(string[] args) 
    { 
     IUnityContainer container = new UnityContainer(); 

     container.RegisterType<ILogger, Logger>(); 
     container.AddNewExtension<LoggerExtension>(); 

     var a = container.Resolve<A>(); 
     var b = container.Resolve<B>(); 
     var c = container.Resolve<C>(); 
     var d = container.Resolve<D>(); 
     var x = container.Resolve<X>(); 
    } 
} 

public interface ILogger 
{ 
    Type Type { get; } 
} 

public class Logger : ILogger 
{ 
    private readonly Type _type; 
    public Logger(Type type) 
    { 
     _type = type; 
    } 

    public Type Type { get { return _type; } } 
} 

public class A 
{ 
    public A(ILogger logger) 
    { 
     System.Diagnostics.Debug.Assert(logger.Type == typeof(A)); 
    } 
} 

public class B 
{ 
    public B(ILogger logger) 
    { 
     System.Diagnostics.Debug.Assert(logger.Type == typeof(B)); 
    } 
} 

public class C 
{ 
    public C(A a, D d, B b, ILogger logger) 
    { 
     System.Diagnostics.Debug.Assert(logger.Type == typeof(C)); 
    } 
} 

public class D 
{ 
    public D() 
    { 
    } 
} 

public class X 
{ 
    public X(Y y) 
    { 
    } 
} 

public class Y 
{ 
    public Y(ILogger logger) 
    { 
     System.Diagnostics.Debug.Assert(logger.Type == typeof(Y)); 
    } 
} 
+0

जोड़ा गया बग फिक्स और एक और परीक्षण केस। –

+0

अच्छा, धन्यवाद! बस कोशिश की, और यह ठीक काम करता है। मुझे अभी भी यह समझने के लिए कोड देखना है कि यह कैसे काम करता है, लेकिन ऐसा लगता है कि मैं वही कर रहा हूं जो मैं चाहता हूं। –

+0

मैंने कोड का क्या कर रहा है इसका विवरण थोड़ा सा जोड़ा। इसके अलावा, मैं हल किए गए कंक्रीट लॉगर प्रकार का उपयोग कर रहा हूं, न कि आईएलओगर इंटरफ़ेस। इसके बजाय ILogger इंटरफ़ेस का उपयोग करना संभव होना चाहिए ('context.OriginalBuildKey' का उपयोग करें) या 'लॉगजर एक्सटेंशन' के पैरामीटर के रूप में ओवरराइड करने के लिए इच्छित कंक्रीट प्रकार जोड़ें। –

0

जैसा कि @ स्पॉटको सुझाव दिया गया है, मैं जेनिक्स की भी सिफारिश करता हूं। जैसा कि यहां दिखाया गया है, "खुली जेनेरिक" का उपयोग करके एकता पंजीकरण किया जाएगा। यह एकल पंजीकरण आपको लॉगर के जेनेरिक पैरामीटर में किसी भी प्रकार को हल करने की क्षमता देता है।

unityContainer.RegisterType(typeof(ILogger<>), typeof(Logger<>)); 

उस पंजीकरण का उपयोग करके, आप इस तरह के कन्स्ट्रक्टर इंजेक्शन का उपयोग करके इंस्टेंस को हल कर सकते हैं।

public class MyClass 
{ 
    public MyClass(ILogger<MyClass> logger) { ... } 
} 

More info here

+0

धन्यवाद, लेकिन यह नहीं है कि मैं क्या करने की कोशिश कर रहा हूं। मैं अपना इंटरफ़ेस जेनेरिक नहीं बनाना चाहता हूं। –

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