【问题标题】:When to use TryAddSingleton or AddSingleton?何时使用 TryAddSingleton 或 AddSingleton?
【发布时间】:2018-06-19 12:47:47
【问题描述】:

我注意到在一些 .NET Core 示例中,在注册服务时调用了 TryAddSingleton,而在一些 AddSingleton 中。

如果服务类型尚未注册,反编译器会显示 TryAdd(由 TryAddSingleton 调用)将指定的参数“描述符”添加到“集合”中。

这是否意味着使用 TryAddSingleton 总是更安全,以防万一其他方法/库已经注册了同一个类?

【问题讨论】:

    标签: c# asp.net-core dependency-injection


    【解决方案1】:

    正如您已经注意到的,TryAddSingletonAddSingleton 之间的区别在于 AddSingleton 始终将注册附加到集合中,而 TryAddSingleton 仅在给定服务类型不存在注册时才这样做。

    当同一服务类型存在多个注册,但请求一个实例时,.NET Core 将始终返回最后一个注册。这意味着AddSingleton的行为是有效地替换非集合解析的实例,例如:

    services.AddSingleton<IX, A>();
    services.AddSingleton<IX, B>(); // ‘replaces’ A
    IX x = container.GetService<IX>(); // resolves B
    

    然而,对于集合解析,AddSingleton 表现为该服务类型的现有注册的集合“附加”。例如:

    services.AddSingleton<IX, A>();
    services.AddSingleton<IX, B>();
    IEnumerable<IX> xs = container.GetServices<IX>(); // resolves A *and* B
    

    但是,对于TryAddSingleton,如果给定服务类型已经存在注册,则不会添加注册。这意味着,无论何时将服务类型解析为一个实例或一组实例,当至少有一个注册时,都不会添加该注册。例如:

    services.TryAddSingleton<IX, A>(); // adds A
    services.TryAddSingleton<IX, B>(); // does not add B, because of A
    IX x = container.GetService<IX>(); // resolves A
    
    services.TryAddSingleton <IX, A>(); // adds A
    services.TryAddSingleton <IX, B>(); // does not add B, because of A
    IEnumerable<IX> xs = container.GetServices<IX>(); // resolves A only
    

    TryAddSingleton 对于希望将自己的组件注册到容器的框架和第三方库代码特别有用。它允许应用程序开发人员覆盖框架或库的默认注册,即使应用程序开发人员在调用框架或第三方 AddXXX 扩展方法之前注册了该组件。例如:

    services.TryAddSingleton<IX, A>(); // adds A
    services.AddThirdPartyLibrary(); // calls services.TryAddSingleton<IX, B>();
    IX x = container.GetService<IX>(); // resolves A
    

    如果第三方库调用了AddSingleton 而不是TryAddSingleton,则应用程序开发人员的A 将始终被覆盖,这可能会导致意外行为。作为应用程序开发人员,您通常知道自己注册了什么,这使得TryAddSingleton 在这种情况下的用处不大。

    我什至会争辩说,从应用程序开发人员的角度来看,AddSingleton 的行为可能非常棘手,因为它隐含地覆盖了现有注册,而没有任何警告。我的经验是,这种行为可能会导致难以发现配置错误。更安全的设计应该是使用AddSingletonAppendSingletonReplaceSingleton 方法,其中AddSingleton 会在注册存在的情况下抛出异常,而ReplaceSingleton 实际上会丢弃现有的注册。

    【讨论】:

      猜你喜欢
      • 2020-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-07
      • 2022-11-12
      • 2021-11-08
      • 1970-01-01
      • 2021-09-07
      相关资源
      最近更新 更多