When to use TryAddSingleton or AddSingleton?

余生颓废 提交于 2019-12-06 20:05:48

问题


I've noticed in some .net core examples there are calls to TryAddSingleton, and in some AddSingleton when registering services.

Decompiler shows that TryAdd( called by TryAddSingleton) adds the specified param "descriptor" to the "collection" if the service type hasn't been already registered.

Does it mean that it always safer to use TryAddSingleton, in case if some other method/library already registered the same class?


回答1:


As you already noticed, the difference between TryAddSingleton and AddSingleton is that AddSingleton always appends the registration to the collection, while TryAddSingleton only does this when there exists no registration for the given service type.

When multiple registrations exist for the same service type, but one instance is requested, .NET Core will always return the last one. This means that the behavior of AddSingleton is to replace instances for non-collection resolves. For instance:

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

For collection resolves however, AddSingleton behaves completely different, because in that case AddSingleton behaves as a collection ‘append’ of already existing registrations for that service type. For instance:

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

With TryAddSingleton however, the registration will not be added when there already exist registrations for the given service type. This means that, independently of when a service type is resolved as one instance or as a collection of instances, the registration will not be added when there is at least one registration. For instance:

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

TryAddSingleton is especially useful for framework and third-party library code that wishes to register its own components to the container. It allows an application developer to override the framework or library’s default registration, even if the application developer registered that component before the framework or third-party AddXXX extension method is called. For instance:

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

Would the third-party library have called AddSingleton instead of TryAddSingleton, the application developer’s A will always be overridden, which can be confusing for the developer. As an application developer, you typically know what you registered, which makes the use of TryAddSingleton not that useful for an application developer.

I would even argue that, from perspective of an application developer, the behavior of AddSingleton can be very tricky, because it implicitly overrides an existing registration, without any warning whatsoever. My experience is that this behavior can cause hard to spot configuration errors. A safer design would have been to have AddSingleton, AppendSingleton and ReplaceSingleton methods, where AddSingleton would throw an exception in case a registration exists, and ReplaceSingleton would actually throw away the existing registration.



来源:https://stackoverflow.com/questions/48185894/when-to-use-tryaddsingleton-or-addsingleton

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!