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