尝试使用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失败。如何将这些装饰器与工厂联系起来?
答案 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();
}
}