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

时间:2013-12-21 07:03:47

标签: c# ninject decorator factory

尝试使用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();
  }
}

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

2 个答案:

答案 0 :(得分:6)

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

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

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

kernel.Bind<IConnectorFactory>().ToFactory(() => new CustomInstanceProvider());

其中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;
    }
}

答案 1 :(得分:0)

没有ninject可以做到这一点,但是我仍然想知道是否有更好的方法来实现它。

public class CoreConnectorFactory : IConnectorFactory
{
  private static CoreConnector conn;
  public IConnector CreateConnector(string id)
  {
    if (conn==null) conn = new CoreConnector();
    return conn;
  }
}

public class LoggingConnectorFactory : IConnectorFactory
{
  private readonly IConnectorFactory cf;
  public LoggingConnectorFactory(IConnectorFactory cf)
  {
    this.cf = cf;
  }
  public IConnector CreateConnector(string id)
  {
    return new LoggingConnector(cf.CreateConnector(id),id);
  }
}

public class AuditingConnectorFactory : IConnectorFactory
{
  private readonly IConnectorFactory cf;
  public AuditingConnectorFactory(IConnectorFactory cf)
  {
    this.cf = cf;
  }
  public IConnector CreateConnector(string id)
  {
    return new AuditingConnector(cf.CreateConnector(id),id);
  }
}
class Tests
{
  public static void Test()
  {
    var coreConnectorFactory     = new CoreConnectorFactory();
    var auditingConnectorFactory = new AuditingConnectorFactory(coreConnectorFactory);
    var loggingConnectorFactory  = new LoggingConnectorFactory(auditingConnectorFactory);
    var connector                = loggingConnectorFactory.CreateConnector("12345");
    connector.Connect();
  }
}