3

我如何可以綁定InitializerForXXX使用Ninject Conventions因此,對於一個IInitializer<T>請求解決非通用實現,其名稱開始(非通用實現)IInitializer<XXX>(通用接口)與InitializerFor和一端與typeof(T).Name像:如何綁定使用Ninject約定擴展泛型類型與繼承

initializerFactory.CreateFor<Blue>();  //resolves InitializerOfBlue 
initializerFactory.CreateFor<ShadeOfBlue>(); //resolves InitializerOfShadeOfBlue 

在沒有非抽象類直接實現IInitializer<T>,並且一些實現方式中從其他實現中繼承:

InitializerForBlue
  • InitializerForBlue繼承
    • InitializerForShadeOfBlue繼承抽象Initializer<Blue>
    • 抽象Initializer<T>直接實現IInitializer<T>

    我希望我可以用一個給定的IInitializer<T>約定,我可以使用一個.EndsWith(typeof(T).Name),因爲有幾百個初始化程序在ShadeOfxxx靜脈中。如果我必須映射它們,我最好找到一種在運行時用反射來解決的方法。

    考慮以下幾點:

    更新:使用自定義綁定發生器綁定(見我的回答如下實施)

    void Bootstrap(IBindingRoot kernel) 
        { 
         kernel.Bind<IInitializerFactory>() 
          .To<InitializerFactory>() 
          .InSingletonScope(); 
    
         kernel.Bind(scanner => 
            scanner.FromThisAssembly().SelectAllClasses() 
             .WhichAreNotGeneric() 
             .InheritedFrom(typeof(IComplexContent)) 
             .BindAllInterfaces()); 
    
         kernel.Bind(scanner => 
            scanner.FromThisAssembly().SelectAllClasses() 
             .WhichAreNotGeneric() 
             .InheritedFrom(typeof(IInitializer<>)) 
             .BindWith<FirstTypeParameterNameMatchesEndOfBoundClassNameGenerator>()); 
        } 
    

    主要方法

    void Main(IEnumerable<string> values) 
    { 
        // setup bindings 
        var kernel = new StandardKernel(); 
        Bootstrap(kernel); 
    
        IInitializerFactory initializerFactory = 
         kernel.Get<IInitializerFactory>(); 
    
        IInitializer<ShadeOfBlueComplexContent> initializer = 
         initializerFactory.CreateFor<ShadeOfBlueComplexContent>(); 
    
        initializer.Initialize(values); 
    } 
    

    初始化廠

    interface IInitializerFactory 
    { 
        IInitializer<T> CreateFor<T>() where T : class, IComplexContent, new(); 
    } 
    
    class InitializerFactory : IInitializerFactory 
    { 
        public IInitializer<T> CreateFor<T>() where T : class, IComplexContent, new() 
        { 
         return MagicallyGetInitializer<T>(); 
        } 
    
        //behind the curtain, whirring noises are heard as 't' is resolved... 
        private static IInitializer<T> MagicallyGetInitializer<T>() 
         where T : class, IComplexContent, new() 
        { 
         IInitializer<T> i = null; 
         return i; 
        } 
    } 
    

    初始化

    interface IInitializer<out T> where T : IComplexContent 
    { 
        T Initialize(IEnumerable<string> values); 
    } 
    
    abstract class Initializer<T> : IInitializer<T> where T : IComplexContent 
    { 
        public abstract T Initialize(IEnumerable<string> values); 
    } 
    
    class InitializerOfBlue : Initializer<Blue> 
    { 
        private readonly Blue _content; 
    
        public InitializerOfBlue(Blue content) {_content = content;} 
    
        public override Blue Initialize(IEnumerable<string> values) 
        { 
         _content.BlueSpecificProperty = values.ElementAt(0); 
         //... populate other blue-specific properties like this 
         return _content; 
        } 
    } 
    
    class InitializerOfShadeOfBlue : InitializerOfBlue 
    { 
        public InitializerOfShadeOfBlue(ShadeOfBlue content) : base(content){} 
    } 
    

    內容模型

    interface IComplexContent 
    { 
        string OneBasicProperty { get; set; } 
        // other properties are specific to implementation 
        string UniqueOperation(); 
    } 
    
    abstract class BaseComplexContent : IComplexContent 
    { 
        public string OneBasicProperty { get; set; } 
        public abstract string UniqueOperation(); 
    } 
    
    class Blue : BaseComplexContent 
    { 
        // initializer sets this 
        public string PropertyForAllKindsOfBlue { get; set; } 
    
        // initializer doesn't interact with this 
        public override string UniqueOperation() {return "I'm plain.";} 
    } 
    
    class ShadeOfBlue : Blue 
    { 
        // initializer doesn't interact with this 
        public override string UniqueOperation() {return "I'm fabulous!";} 
    } 
    
  • 回答

    5

    您是在指定的類選擇

    kernel.Bind(scanner => 
           scanner.FromThisAssembly().SelectAllClasses() 
            .WhichAreNotGeneric() 
            .InheritedFrom(typeof (IInitializer<>)) 
    

    這已經足夠了。你需要做的是添加一個自定義綁定生成器。對於InitializerForShadeOfBlue

    https://github.com/ninject/ninject.extensions.conventions/wiki/Projecting-Services-to-Bind

    +0

    好了,我要在那一刀,然後再發布更新。爲此,從AbstractInterfaceBindingGenerator繼承還是實現IBindingGenerator更好?我注意到現有的做或者/或者。 – Jeff 2013-03-07 01:18:34

    +0

    @Lumirris代碼(和wiki IIRC)有答案(一般比較喜歡'AbstractInterfaceBindingGenerator',除非你碰到一個障礙,你不能通過實現基本接口或者通過拉請求來避開) – 2013-03-07 09:11:43

    0

    BEGIN解候選選擇IInitializer<Blue>InitializerForBlueIInitializer<ShadeOfBlue> - 自定義綁定發生器:

    定製綁定發生器

    謝謝你的建議,@RemoGloor和@RubenBartelink。我很難過 - 問題在於我將IInitializer<Blue>綁定到InitializerOfShadeOfBlue。我需要能夠以某種方式將Blue中的泛型類型參數更改爲IInitializer<Blue>綁定候選中的ShadeOfBlue,因爲IInitializer<ShadeOfBlue>是在運行時將從工廠方法請求的內容。

    有沒有辦法修改綁定候選的泛型類型參數列表?或者我吠叫錯誤的實施?任何編輯建議給我的OP或這個答案,讚賞。

    /// <summary>Creates bindings on open generic types where bound implementations' 
    /// names end with the name of the generic type argument</summary> 
    public class FirstTypeParameterNameMatchesEndOfBoundClassNameGenerator : IBindingGenerator 
    { 
        public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot) 
        { 
         if (type == null) throw new ArgumentNullException("type"); 
         if (bindingRoot == null) throw new ArgumentNullException("bindingRoot"); 
    
         // only consider concrete, non-abstract classes 
         if (type.IsInterface || type.IsAbstract) yield break; 
    
         var bindingType = GetBindingType(type); 
    
         if (bindingType != null) 
          yield return bindingRoot.Bind(bindingType).To(type); 
         // ARGH! bindingType == IInitializer`1[[Blue]] but I want 
         // IInitializer`1[[ShadeOfBlue]] for type == ShadeOfBlue 
    
        } 
    
        private static Type GetBindingType(Type type) 
        { 
         Type goodMatch = null; 
    
         foreach (var candidate in type.GetInterfaces()) 
         { 
          // skip non-generic interfaces 
          if (!candidate.IsGenericType) continue; 
    
          // assumption: using argument in first position 
          var firstArg = candidate.GetGenericArguments().First(); 
          if (!type.Name.EndsWith(firstArg.Name)) continue; 
    
          // IInitializer<XXX> matches InitializerOfXXX 
          goodMatch = candidate; 
          break; 
         } 
         if (goodMatch == null) 
         { 
          // if no match on interfaces, walk through the ancestor types 
          foreach (var candidate in type.GetAllAncestors()) 
          { 
           goodMatch = GetBindingType(candidate); 
           if (goodMatch != null) break; 
          } 
         } 
         return goodMatch; 
        } 
    

    類型擴展幫手

    public static class TypeExtensions 
    { 
        // returns all ancestor types starting with the parent 
        public static IEnumerable<Type> GetAllAncestors(this Type type) 
        { 
         for (var current = type.BaseType; current != null; current = current.BaseType) 
          yield return current; 
        } 
    } 
    

    END解候選 - 自定義綁定發電機

    +0

    Ninject不能做任何事C#不能。 'InitializerOfShadeOfBlue'沒有實現'IInitializer '接口。你必須先把它弄好。 – 2013-03-10 13:31:06

    +0

    @RemoGloor但它從'InitializerOfBlue'繼承,'InitializerOfBlue'繼承自'Initializer '。我正在研究一些將'InitializerOfShadeBlue'的類型祖先樹爬上來的東西,直到它找到'Initializer ',抓住'Blue'的GenericTypeArgment,然後檢查'Blue'子類的程序集以找到'ShadeOfBlue'。然後它使用'ShadeOfBlue'來建立'IInitializer '的泛型類型定義,我可以將它綁定到'InitializerOfShadeOfBlue'.我覺得我現在距離兔子洞很遠,但是我會試着去獲得它工作併發布它。 – Jeff 2013-03-11 01:00:21

    +0

    @Lumrirris沒有抱歉,如果InitializerOfShadeOfBlue沒有實現IInitializer 沒有辦法把它轉換到這個接口。 – 2013-03-11 01:08:03