查看代理生成代码:
https ://github.com/ninject/ninject.extensions.interception/blob/master/src/Ninject.Extensions.Interception.DynamicProxy/DynamicProxyProxyFactory.cs
if (targetType.IsInterface)
{
reference.Instance = this.generator.CreateInterfaceProxyWithoutTarget(targetType, additionalInterfaces, InterfaceProxyOptions, wrapper);
}
else
{
object[] parameters = context.Parameters.OfType<ConstructorArgument>()
.Select(parameter => parameter.GetValue(context, null))
.ToArray();
reference.Instance = this.generator.CreateClassProxy(targetType, additionalInterfaces, ProxyOptions, parameters, wrapper);
}
可以看到ninject的动态代理扩展只是将ConstructorArgument
s传递给Castle Dynamic Proxy Generator。
因此 - 无需更改 ninject 扩展或创建自己的扩展 - 您需要将所有依赖项作为构造函数参数传递。您还可以尝试属性/方法注入是否有效(请参阅https://github.com/ninject/ninject/wiki/Injection-Patterns)。
如果您控制代码,则可以将接口添加到代理类,然后使用“带目标的接口代理”。这允许将代理实例化与目标(代理类)实例化分离——>目标可以注入依赖项ctor,而无需对 ninject(-extensions)进行任何更改。
澄清:具有以下应代理的类:
public interface IBar { }
public class Foo
{
public Foo(IBar bar)
{
}
}
以及以下绑定:
Bind<Foo>().ToSelf().Intercept().With<SomeInterceptor>();
Bind<IBar>().To<Bar>();
然后Foo
从 ninject 容器中检索 a:
IResolutionRoot.Get<Foo>();
不会工作。
将所有构造函数参数放在 ninject 上下文中以使其工作
但是,我们可以更改检索Foo
以使其工作:
var bar = IResolutionRoot.Get<IBar>();
IResolutionRoot.Get<Foo>(new ConstructorArgument("bar", bar);
现在这是次优的,因为 ninject 不会自动进行依赖解析。
向代理类添加接口以使其更好地工作
我们可以通过使用“带目标的接口代理”来解决这个问题。首先,我们为代理类添加一个接口:
public interface IFoo{ }
public class Foo : IFoo
{
public Foo(IBar bar)
{
}
}
然后我们将绑定更改为:
Bind<IFoo>().To<Foo>().Intercept().With<SomeInterceptor>();
然后Foo
从 ninject 容器中检索 a:
IResolutionRoot.Get<Foo>();
作品。
另一个可能更简单(&uglier?)的解决方案
根据@Daniel,这可行:将两个构造函数添加到代理类型:
- 一个
protected
没有参数的构造函数。这个是给 DynamicProxy 创建代理的。
- 一个
public
/internal
带有参数的构造函数,用于 ninject 实例化代理类型。
Ninject 将自动选择具有最多可解析参数的构造函数。