c# - 何时使用 TryAddSingleton 或 AddSingleton?

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

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

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

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

最佳答案

正如您已经注意到的,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 实际上会丢弃现有的注册。

关于c# - 何时使用 TryAddSingleton 或 AddSingleton?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48185894/

相关文章:

c# - 从 C# 调用 DLL 时,为什么小结构会错位函数参数?

xml - ASPNetCore API 内容协商不起作用

dependency-injection - 从范围服务工厂获取主机名

c# - 如何根据字符串动态调用类?

c# - 在 windows 和 mono linux 平台上显示 RGB 图像

c# - JSON.Net:反序列化多态类型而不指定程序集

c# - .NET Core 不依赖于任何安装?

c# - 连接字符串时,razor 不接受空格作为第一个字符吗?

java - 如何将 thenReturn() 与注入(inject)的 @Mock 类一起使用?

c# - 在 C# 中编写等效的 IsDate()?