2016-12-15 34 views
0

我想聚集我的注入對象到一個數據對象,所以我不必有大的構造函數列表。不過,我仍然希望使用WhenInjectedInto來提供上下文綁定。如何重構ninject注入到一個更乾的形式

例如下面的規格測試,我相信這將有助於

WhenInjectedIntoRequestChain

表示只應使用綁定在源 已經注入被注入parent0其本身所具有的情景已注入父母1等

該方法應具有簽名

public static IBindingInNamedWithOrOnSyntax<T> 
     WhenInjectedIntoRequestChain<T> 
      (this IBindingWhenInNamedWithOrOnSyntax<T> @this 
      , params Type[] parentChain 
      ) 

用於測試該規範,這應該是

using System.Collections.Generic; 
using System.Linq; 
using FluentAssertions; 
using Ninject; 
using Weingartner.Controls.PluginFramework; 
using Xunit; 

namespace Weingartner.Controls.Spec.PluginFramework 
{ 
    public class NinjectExtensionsSpec 
    { 
     public interface IData { } 

     public class Data0 : IData {} 
     public class Data1 : IData {} 
     public class Data2 : IData {} 

     public class Params 
     { 
      public IList<IData> Data { get; set; } 

      public Params(IEnumerable<IData> data) 
      { 
       Data = data.ToList(); 
      } 

     } 

     public class Target0 
     { 
      public Params P { get; set; } 
      public Target0(Params p) {P = p;} 
     } 

     public class Target1 
     { 
      public Params P { get; set; } 
      public Target1(Params p){P = p;} 
     } 

     [Fact] 
     public void WhenInjectedIntoHeirarchyShouldWork() 
     { 
      var k = new StandardKernel(); 

      k.Bind<IData>().To<Data0>() 
      .WhenInjectedIntoRequestChain(typeof(Params),typeof(Target0)); 
      k.Bind<IData>().To<Data1>() 
      .WhenInjectedIntoRequestChain(typeof(Params),typeof(Target1)); 
      k.Bind<IData>().To<Data2>() 
      .WhenInjectedIntoRequestChain(typeof(Params),typeof(Target1)); 


      var target0 = k.Get<Target0>(); 
      var target1 = k.Get<Target1>(); 

      target0.P.Data.Count.Should().Be(1); 
      target1.P.Data.Count.Should().Be(2); 


     } 

    } 
} 

回答

0

這裏是一個解決上述問題的一些測試用例。這不是上述問題的確切解決方案,但是這種新方法可以解決上述問題。

using System; 
using System.Linq; 
using Ninject.Activation; 
using Ninject.Infrastructure.Language; 
using Ninject.Syntax; 

namespace Weingartner.Controls.PluginFramework 
{ 
    public static class NinjectExtensions 
    { 

     /// <summary> 
     /// Indicates that the binding should only be used where the source 
     /// has been injected into parentChain[0] which in turn has been injected 
     /// into parentChain[1] and son on 
     /// </summary> 
     /// <param name="parentChain">This list of parents in order</param> 
     /// <returns>The fluent syntax.</returns> 
     public static IBindingInNamedWithOrOnSyntax<T> 
      WhenInjectedIntoRequestChain<T> 
       (this IBindingWhenInNamedWithOrOnSyntax<T> @this 
       , params Type[] parentChain 
       ) 
     { 

      @this.BindingConfiguration.Condition = 
       request => 
       { 
        var result = true; 
        foreach (var parent in parentChain) 
        { 
         result = result && WhenInjectedInto(request, parent); 
         request = request?.ParentRequest; 
        } 
        return result; 
       }; 

      return (IBindingInNamedWithOrOnSyntax<T>)@this; 
     } 

     private static bool WhenInjectedInto(IRequest request, Type parent) 
     { 
      if (!parent.IsGenericTypeDefinition) 
       return request?.Target != null 
        && parent.IsAssignableFrom(request.Target.Member.ReflectedType); 

      if (!parent.IsInterface) 
       return request 
        ?.Target?.Member.ReflectedType 
        .GetAllBaseTypes() 
        .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == parent) 
        ?? false; 

      return request 
       ?.Target?.Member.ReflectedType? 
       .GetInterfaces() 
       .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == parent) 
       ?? false; 
     } 
    } 
}