ninject - 使用工厂模式将泛型参数传递给装饰器链

phi*_*hil 3 c# factory ninject decorator

尝试使用ninject将泛型参数传递给装饰器链时遇到了问题.也许最好用代码解释一下:

public interface IConnector
{
  void Connect();
}

public class CoreConnector : IConnector
{
  public void Connect()
  {
    Console.WriteLine("core connector");
  }
}

public class LoggingConnector : IConnector
{
  private readonly IConnector conn;
  private string id;
  public LoggingConnector(IConnector conn, string id)
  {
    this.conn = conn;
    this.id = id;
  }
  public void Connect()
  {
    Console.WriteLine("logging conn id : {0}",id);
    conn.Connect();
  }
}

public class AuditingConnector : IConnector
{
  private readonly IConnector conn;
  private string id;
  public AuditingConnector(IConnector conn, string id)
  {
    this.conn = conn;
    this.id = id;
  }
  public void Connect()
  {
    Console.WriteLine("auditing conn id : {0}", id);
    conn.Connect();
  }
}

public interface IConnectorFactory
{
  IConnector CreateConnector(string id);
}
class Tests
{
  public static void Test0()
  {
    var kernel = new StandardKernel();
    kernel.Bind<IConnector>().To<CoreConnector>().WhenInjectedInto<LoggingConnector>().InSingletonScope();
    kernel.Bind<IConnector>().To<LoggingConnector>();
    kernel.Bind<IConnectorFactory>().ToFactory();

    var factory = kernel.Get<IConnectorFactory>();
    var connector = factory.CreateConnector("12345");
    connector.Connect();
  }

  public static void Test1()
  {
    var kernel = new StandardKernel();
    kernel.Bind<IConnector>().To<CoreConnector>().WhenInjectedInto<AuditingConnector>().InSingletonScope();
    kernel.Bind<IConnector>().To<AuditingConnector>().WhenInjectedInto<LoggingConnector>();
    kernel.Bind<IConnector>().To<LoggingConnector>();
    kernel.Bind<IConnectorFactory>().ToFactory();

    var factory = kernel.Get<IConnectorFactory>();
    var connector = factory.CreateConnector("12345");
    connector.Connect();
  }
}
Run Code Online (Sandbox Code Playgroud)

显然,Test0通过,Test1失败.如何将这些装饰器与工厂联系起来?

sha*_*p00 6

您可以使用激活上下文来查找父构造函数中使用的参数.像这样:

kernel.Bind<IConnector>()
    .To<AuditingConnector>()
    .WhenInjectedInto<LoggingConnector>()
    .WithConstructorArgument("id", 
       ctx => ctx.Request.ParentContext.Parameters
         .Single(x => x.Name == "id")
         .GetValue(ctx, null));
Run Code Online (Sandbox Code Playgroud)

或者,您可以设置自定义实例提供程序以与工厂一起使用,该工具将参数传递到链中:

kernel.Bind<IConnectorFactory>().ToFactory(() => new CustomInstanceProvider());
Run Code Online (Sandbox Code Playgroud)

其中CustomInstanceProvider如下:

public class CustomInstanceProvider : StandardInstanceProvider
{
    protected override ConstructorArgument[] GetConstructorArguments(MethodInfo methodInfo, object[] arguments)
    {
        var parameters = methodInfo.GetParameters();
        var constructorArguments = new ConstructorArgument[parameters.Length];
        for (int i = 0; i < parameters.Length; i++)
        {
            constructorArguments[i] = new ConstructorArgument(parameters[i].Name, arguments[i], true);
        }
        return constructorArguments;
    }
}
Run Code Online (Sandbox Code Playgroud)