何时使用TryAddSingleton或AddSingleton?

MiF*_*vil 13 c# dependency-injection startup asp.net-core

我注意到在一些.net核心示例中有调用 TryAddSingleton,有些是 AddSingleton在注册服务时.

如果服务类型尚未注册,则反编译器会显示TryAdd(由TryAddSingleton调用)将指定的参数"descriptor"添加到"集合".

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

Ste*_*ven 28

正如你已经注意到了,之间的区别TryAddSingleton,并AddSingletonAddSingleton总是附加登记到集合,而TryAddSingleton只有做到这一点,当存在针对给定服务类型没有注册.

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

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

但是,对于集合结果,AddSingleton行为完全不同,因为在这种情况下AddSingleton表现为该服务类型的现有注册的集合"附加".例如:

services.AddSingleton<IX, A>();
services.AddSingleton<IX, B>();
IEnumerable<IX> xs = container.GetServices<IX>(); // resolves A and B
Run Code Online (Sandbox Code Playgroud)

随着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
Run Code Online (Sandbox Code Playgroud)

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

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

如果第三方库调用AddSingleton而不是TryAddSingleton,应用程序开发人员A将始终被覆盖,这可能会让开发人员感到困惑.作为应用程序开发人员,您通常知道自己注册了什么,这使得对TryAddSingleton应用程序开发人员的使用不那么有用.

我甚至认为,从应用程序开发人员的角度来看,行为AddSingleton可能非常棘手,因为它隐含地覆盖了现有的注册,没有任何警告.我的经验是,这种行为可能导致很难发现配置错误.一个更安全的设计本来就有AddSingleton,AppendSingleton以及ReplaceSingleton方法,如果AddSingleton存在注册会抛出异常,并且ReplaceSingleton实际上会丢弃现有的注册.

  • 谢谢你!这个答案激励我完成我的图书馆的工作。https://github.com/ezzabuzaid/tiny-injector 我添加了上述功能,效果非常好! (3认同)