web-dev-qa-db-ja.com

どのような場合にTryAddSingletonまたはAddSingletonを使用しますか?

一部の.netコアの例ではTryAddSingletonへの呼び出しがあり、一部のAddSingletonではサービスを登録するときに気づきました。

デコンパイラーは、サービスタイプがまだ登録されていない場合、TryAdd(TryAddSingletonによって呼び出されます)が指定されたパラメーター「記述子」を「コレクション」に追加することを示します。

他のメソッド/ライブラリがすでに同じクラスを登録している場合に、TryAddSingletonを使用するほうが常に安全であることを意味しますか?

14

すでにお気づきのとおり、TryAddSingletonAddSingletonの違いは、AddSingletonが常にコレクションに登録を追加するのに対し、TryAddSingletonは、存在する場合にのみこれを行うということです。指定されたサービスタイプの登録はありません。

同じサービスタイプに複数の登録が存在する場合、1つのインスタンスが要求されると、.NET Coreは常に最後のインスタンスを返します。つまり、AddSingletonの動作は、非コレクション解決のインスタンスを置き換えることです。例えば:

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

ただし、コレクション解決の場合、AddSingletonの動作は完全に異なります。その場合、AddSingletonは、そのサービスタイプの既存の登録の「追加」コレクションとして動作するためです。例えば:

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

ただし、TryAddSingletonを使用すると、指定されたサービスタイプの登録がすでに存在する場合、登録は追加されません。つまり、サービスタイプが1つのインスタンスまたはインスタンスのコレクションとして解決される場合とは関係なく、少なくとも1つの登録がある場合、登録は追加されません。例えば:

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は、独自のコンポーネントをコンテナに登録する必要があるフレームワークおよびサードパーティのライブラリコードに特に役立ちます。これにより、アプリケーション開発者は、フレームワークまたはサードパーティの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の動作は非常に注意が必要な場合もあります。何の警告もなく、既存の登録を暗黙的にオーバーライドするためです。私の経験では、この動作により構成エラーを特定することが困難になる可能性があります。より安全な設計は、AddSingletonAppendSingleton、およびReplaceSingletonメソッドを使用することでした。ここで、AddSingletonは、登録が存在する場合に例外をスローし、ReplaceSingletonは実際には既存の登録を破棄します。

33
Steven