Ninject:将构造函数参数绑定到其他对象的属性
我有一个IConfig
对象,其中包含我的应用程序中使用的设置。 此刻,我将整个对象注入到需要它的每个对象的构造函数中,如下所示:
public interface IConfig { string Username { get; } string Password { get; } //... other settings } public class Foo : IFoo { private readonly string username; private readonly string password; public Foo(IConfig config) { this.username = config.Username; this.password = config.Password; } }
缺点是IConfig
包含大量设置,因为它是从整个配置文件中反序列化的,因此不需要注入整个对象。 我想要做的是将构造函数更改为Foo(string username, string password)
以便它只接收所需的设置。 这也使得为测试创建Foo
对象变得更加容易(不必仅仅为了创建Foo
而设置IConfig
)。 我想直接在我的NinjectModule
绑定构造函数参数,如下所示:
public class MyModule : NinjectModule { public override void Load() { Bind().To() .InSingletonScope(); Bind().To() .WithConstructorArgument("username", IConfig.Username) .WithConstructorArgument("password", IConfig.Password); } }
显然这段代码不起作用,但我怎么去做我想要的呢?
我最初的想法是使用NinjectModule.Kernel
来获取IKernel
然后获取我的IConfig
对象的实例并根据需要注入属性,但是NinjectModule.Kernel
返回的对象没有Get()
方法。
你走在正确的轨道上:
Kernel.Get
方法是在Ninject
namepsace中的ResolutionExtensions
上定义的扩展方法,因此添加了using Ninject;
它也可以在您的模块中使用。
但是,您应该使用在Module.Kernel
的第二个重载中提供的IContext
来获取Kernel
,而WithConstructorArgument
:
Bind().To() .WithConstructorArgument("username", context => context.Kernel.Get().Username) .WithConstructorArgument("password", context => context.Kernel.Get ().Password);
这可能是接口隔离原则的良好假设。
在这种情况下,定义另一个接口,例如ICredentialConfig
包含Username
和Password
属性的IConfig
,然后使IConfig
实现此接口。
public Interface ICredentialConfig { string Username { get; } string Password { get; } } public Interface IConfig : ICredentialConfig { //... other settings }
现在让Foo
依赖于ICredentialConfig
而不是IConfig
。 然后你可以:
- 使用Ninject注入
JsonConfig
,而不是使用硬编码的参数名称。 - 实现/模拟
ICredentialConfig
以在测试中实例化Foo
,而不必实现完整的IConfig
接口。