[英]Simple Injector explicit attribute injection - property is null inside constructor
Simple Injector 的新手,试图让一些部件为原型工作。 我正在创建一个使用 Simple Injector 和 ReactiveUI 的 WPF 应用程序,但似乎无法通过属性来触发显式属性注入。 我正在处理的具体示例只是测试记录器的注入。 计划是将其滚动到装饰器中,但我已经遇到了使用以前的项目/DI 库进行属性注入的需要。 只是想验证我能够使用它。
引导的片段:
private Container RegisterDependencies(Container container = null)
{
container ??= new Container();
// Container initialization that must precede dependency registration
// occurs here
// Enable property injection via the [Import] attribute
container.Options.PropertySelectionBehavior =
new ImportPropertySelectionBehavior();
SimpleInjectorInitializer initializer = new SimpleInjectorInitializer();
Locator.SetLocator(initializer);
Locator.CurrentMutable.InitializeSplat();
Locator.CurrentMutable.InitializeReactiveUI();
container.UseSimpleInjectorDependencyResolver(initializer);
container.RegisterConditional(
typeof(ILogger),
c => typeof(NLogLogger<>)
.MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
container.Register<MainWindow>();
container.Register<ISystem, System>(Lifestyle.Singleton);
container.Verify();
return container;
}
从Main
调用的 static RunApplication
中的 DI 容器请求System
的一个实例:
var system = container.GetInstance<ISystem>();
这是系统中的属性注入:
public class System : ISystem
{
[Import] public ILogger Logger { get; set; }
public System()
{
// Logger is null here. NullReferenceException is thrown
Logger.LogInfo("Creating System");
}
}
此时在构造函数中, Logger
属性为 null 并尝试记录失败并出现异常。 我应该提到ILogger
是我自己对 NLog 的抽象。 如果我改为执行构造函数注入:
public System(ILogger logger)
Simple Injector 接受了这一点并很好地解决了依赖关系。 我尝试将Import
属性更改为不同的自定义Dependency
属性,没有变化。 还尝试将记录器实例化为 singleton,行为相同。
真的很感激任何想法,我在搜索论坛、SimpleInjector/ReactiveUI 文档和 Steven 的 DI 书上都快干了。
编辑 - 这里也是 PropertySelectionBehavior 代码:
public class PropertySelectionBehavior<T> : IPropertySelectionBehavior
where T : Attribute
{
public bool SelectProperty(
Type implementationType, PropertyInfo propertyInfo) =>
propertyInfo.GetCustomAttributes(typeof(T)).Any();
}
public class ImportPropertySelectionBehavior :
PropertySelectionBehavior<ImportAttribute> { }
第二次编辑 - 我可以取出所有与 ReactiveUI 相关的初始化并仍然重现相同的行为。 新样本如下所示:
private Container RegisterDependencies(Container container = null)
{
container ??= new Container();
container.Options.PropertySelectionBehavior =
new ImportPropertySelectionBehavior();
// Logger registration
container.RegisterConditional(
typeof(ILogger),
c => typeof(NLogLogger<>)
.MakeGenericType(c.Consumer.ImplementationType),
Lifestyle.Singleton,
c => true);
// UI registration
container.Register<MainWindow>();
//container.Register<MainWindowViewModel>();
container.Register<ISystem, System>(Lifestyle.Singleton);
container.Verify();
return container;
}
更新,显式属性注入工作正常。 它发生在施工后。 我想这是有设计原因的,尽管在某种程度上与我的想法相反,属性注入将按需/首次使用时执行。
计划进行更多试验,以查看在解决属性依赖关系的时间上可用的控制。 如果任何更有经验的人对此有任何建议或可以向我指出其他文档,我会欢迎它。 装饰器听起来像是一种更优雅的方式,可以确保记录器按预期可用,并允许独立延迟加载被装饰者的关注点。 这里有一些讨论:
您正在使用System
构造函数中的Logger
属性。 然而,属性仅在构造函数完成后才被初始化。 如果您从等式中删除 Simple Injector,并回退到普通的旧 C#,您会看到相同的结果。 例如:
var system = new System() // <-- constructor call
{
Logger = new NLogLogger<System>() // Logger_set is called after the ctor
};
如果您运行此代码,您将看到System
的构造函数抛出相同的NullReferenceException
。
这意味着您不应该使用构造函数内部的任何属性。 更广泛地说,从 DI 的角度来看,您不应该在构造函数内部(或在构造过程中)使用任何服务,正如 Mark Seemann 在此处所描述的那样。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.