一部の.netコアの例ではTryAddSingleton
への呼び出しがあり、一部のAddSingleton
ではサービスを登録するときに気づきました。
デコンパイラーは、サービスタイプがまだ登録されていない場合、TryAdd(TryAddSingletonによって呼び出されます)が指定されたパラメーター「記述子」を「コレクション」に追加することを示します。
他のメソッド/ライブラリがすでに同じクラスを登録している場合に、TryAddSingletonを使用するほうが常に安全であることを意味しますか?
すでにお気づきのとおり、TryAddSingleton
とAddSingleton
の違いは、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
の動作は非常に注意が必要な場合もあります。何の警告もなく、既存の登録を暗黙的にオーバーライドするためです。私の経験では、この動作により構成エラーを特定することが困難になる可能性があります。より安全な設計は、AddSingleton
、AppendSingleton
、およびReplaceSingleton
メソッドを使用することでした。ここで、AddSingleton
は、登録が存在する場合に例外をスローし、ReplaceSingleton
は実際には既存の登録を破棄します。