3

나는 IInitializer<XXX> (범용 인터페이스)을 (제네릭이 아닌 구현)을 IInitializer<T> 요청 이름이 시작하는 제네릭이 아닌 구현을 해결할 수 있도록 Ninject Conventions를 사용하여 InitializerForXXX을 결합 할 수있는 방법 같은 typeof(T).Name와 InitializerFor 과 끝 :는 어떻게해서 Ninject 규칙 확장을 사용하여 상속 제네릭 형식을 결합 할

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

더 비 추상 클래스는 직접 IInitializer<T>을 구현없는 경우, 일부 구현은 다른 구현에서 상속 :

를 추상적 인 Initializer<Blue>
  • 추상적 인 Initializer<T>에서 InitializerForBlue
  • InitializerForBlue 상속에서
    • InitializerForShadeOfBlue 상속은 직접 내가 때문에, 내가 사용할 수있는 주어진 IInitializer<T> 규칙에 대한 .EndsWith(typeof(T).Name)를 사용할 수 바라고 있어요 IInitializer<T>

    를 구현 글자 그대로 ShadeOfxxx 정맥에는 수백 개의 초기화자가 있습니다. 모든 것을 매핑해야한다면 런타임시 반영으로 해결할 방법을 찾는 것이 좋습니다.

    다음 감안할 때 :

    UPDATE : 사용자 정의 바인딩 생성기 바인딩은

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

    초기화 공장

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

    주요 방법 (구현에 대한 내 대답은 아래 참조)

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

    이것은 이미 충분합니다. 당신이해야 할 일은 사용자 정의 바인딩 제너레이터를 추가하는 것입니다.즉 https://github.com/ninject/ninject.extensions.conventions/wiki/Projecting-Services-to-Bind

    +0

    좋아, 나는 그에서 자상을 가지고 업데이 트를 게시합니다. 이를 위해 AbstractInterfaceBindingGenerator를 상속하거나 IBindingGenerator를 구현하는 것이 더 좋습니다. 나는 기존의 것들이/또는 어느 쪽인지를한다. – Jeff

    +0

    는 –

    0

    이 해결책 후보자 BEGIN InitializerForShadeOfBlue에 대한 InitializerForBlue에 대한 IInitializer<Blue>IInitializer<ShadeOfBlue>를 선택 - 사용자 정의 바인딩 생성기 : 조언, @RemoGloor 및 대한

    사용자 정의 바인딩 생성기

    감사합니다 @RubenBartelink. 나는 곤란하다. 문제는 내가 IInitializer<Blue>InitializerOfShadeOfBlue에 묶는 것이다. IInitializer<ShadeOfBlue> 런타임시 팩토리 메소드에서 요구 될 것입니다 무엇 때문에 내가 어떻게 든 IInitializer<Blue> 바인딩 후보에 ShadeOfBlueBlue에서 제네릭 형식 인수를 변경 할 수 있어야합니다.

    바인딩 후보의 제네릭 형식 인수 목록을 수정하는 방법이 있나요? 아니면 잘못된 구현을 짖고 있습니까? 내 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; 
        } 
    } 
    

    엔드 솔루션의 후보자 - 사용자 정의 바인딩 생성기

    +0

    Ninject에 아무것도 할 수 없습니다 (당신이 기본 인터페이스를 구현하여 또는 풀의 요청에 의해 주변에 얻을 안 열려 장애물에 충돌하지 않는 한 일반적으로'AbstractInterfaceBindingGenerator'를 선호) 코드 (그리고 위키 IIRC)이 답을 가지고 @Lumirris C# 할 수 없습니다. 'InitializerOfShadeOfBlue'는 'IInitializer '인터페이스를 구현하지 않습니다. 먼저 그걸 가져야 만합니다. –

    +0

    @RemoGloor 그러나, 그것은 차례로 이니셜 '에서 상속'InitializerOfBlue','에서 상속 않습니다. 그때 나는'ShadeOfBlue'을 찾을 수있는'Blue' 서브 클래스에 대한 어셈블리를 검사, 그것은'이니셜 을'발견 Blue''의 GenericTypeArgment를 잡고 때까지 InitializerOfShadeBlue''의 유형 조상 트리를 올라 뭔가 일하고 있어요. 그런 다음 나는 지금 꽤 멀리 토끼 구멍 아래로 해요 같은 느낌 InitializerOfShadeOfBlue'.I'에 결합 할 수 IInitializer ''의 제네릭 형식 정의를 구축하는'ShadeOfBlue'를 사용하지만, 나는 그것을 얻기 위해 노력하겠습니다 일하고 게시하십시오. – Jeff

    +0

    @ Lumrirris InitializerOfShadeOfBlue가 IInitializer 을 구현하지 않으면이 인터페이스로 변환 할 수 없습니다. –