简单注入器显式属性注入 - 属性 在构造函数中为空

Simple Injector explicit attribute injection - property is null inside constructor

Simple Injector 的新手,试图让一些部件为原型工作。我正在创建一个使用 Simple Injector 和 ReactiveUI 的 WPF 应用程序,但似乎无法通过属性触发显式 属性 注入。我正在处理的具体示例只是测试记录器的注入。计划是将其整合到装饰器中,但我 运行 需要使用以前的 projects/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:

调用的静态 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 属性 为空并且尝试记录失败并出现异常。我应该提到 ILogger 是我自己对 NLog 的抽象。如果我改为执行构造函数注入:

public System(ILogger logger)

Simple Injector 接受了这一点并很好地解决了依赖关系。我已尝试将 Import 属性更改为不同的自定义 Dependency 属性,但没有任何变化。还尝试将记录器实例化为单例,相同的行为。

非常感谢任何想法,我 运行正在搜索论坛、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;
}

更新,显式 属性 注入工作正常。它发生在构建之后。我想这是有设计原因的,尽管不知何故这与我的心智模型相反,即 属性 注入将在 on-demand/on 首次使用时执行。

计划进行更多试验,以了解在解决 属性 依赖项的时间上可以使用哪些控制。如果有经验的人对此有任何建议,或者可以指出其他文档,我将非常欢迎。装饰器听起来像是一种更优雅的方式来确保记录器按预期可用并允许独立延迟加载装饰者关注点。这里有一些讨论:

您正在使用内部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 here 所描述的那样在构造函数中(或在构造过程中)使用 any 服务。 =16=]