我注意到在一些 .NET Core 示例中有对 TryAddSingleton
的调用,在一些 AddSingleton
中注册服务时。
如果服务类型尚未注册,反编译器显示 TryAdd(由 TryAddSingleton 调用)将指定的参数“描述符”添加到“集合”。
这是否意味着使用 TryAddSingleton 总是更安全,以防其他方法/库已经注册了相同的类?
最佳答案
正如您已经注意到的,TryAddSingleton
和 AddSingleton
之间的区别在于 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
的行为可能非常棘手,因为它隐式地覆盖了现有的注册,没有任何警告。我的经验是这种行为会导致难以发现配置错误。一个更安全的设计是使用 AddSingleton
、AppendSingleton
和 ReplaceSingleton
方法,其中 AddSingleton
会抛出异常如果注册存在,ReplaceSingleton
实际上会丢弃现有的注册。
关于c# - 何时使用 TryAddSingleton 或 AddSingleton?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48185894/