11

IServiceProvider.GetService(Type serviceType)メソッド署名との意図に違いはありIServiceLocator.GetInstance(Type serviceType)ますか? もしそうなら、違いは何ですか?

私は常にそれらを同等のものとして扱ってきましたが、一貫性を保つために単一の方法を使用することにしました。これは 2 つのインターフェイスを扱うのに十分な解決策のように思えますが、正しい場所で正しいものを使用していることを確認できるように、それらの使用法が実際にどのように意図されていたかを知りたいと思っています。 それらの意図が実際に同じである場合、同じ目的のために複数のセマンティクスのセットを持つ理由はありますか? (の開始時に署名が推奨されていたことは理解してGetInstanceMicrosoft.Practices.ServiceLocationますが、これは重複を導入する正当な理由とは思えません)。

なぜ私は混乱しています

以下は、この質問に対する答えを見つけようとして見つけた矛盾する事実と、それに対する私の解釈のリストです。これらを含めているのは、このトピックについて既に知られているすべての情報のコンテキストで私の質問に対処できるようにするためです.

  • MSDNドキュメントにIServiceProviderは、GetService(Type serviceType)メソッドが返す必要があると書かれています

    タイプserviceType のサービス オブジェクト。
    - または - serviceType型のサービス オブジェクトがない場合は
    null
  • MSDN ドキュメントにIServiceLocatorはメソッドのドキュメントがありませんが、VS オブジェクト ブラウザの概要にはGetInstance(Type serviceType)、メソッドが「要求されたサービス インスタンス」を返すと記載されています。ただし、ドキュメントIServiceLocatorには、サービス インスタンスの解決中にエラーが発生した場合に をスローするActivationException必要があるという例外エントリもあります。

  • ActivationExceptionが導入されてから数年後に導入されたMicrosoft.Practices.ServiceLocation名前空間にありますIServiceProviderIServiceProviderしたがって、が例外を参照していないことは理解できます。そうは言っても、IServiceLocatorインターフェイスのドキュメントにはnull、結果が見つからない場合に戻ることについては何も書かれていません。また、要求されたサービス タイプの実装の欠如が例外を構成する必要があるかどうかも明らかではありません。

  • サービス タイプの実装がない場合、ActivationExceptioninIServiceLocator実装が発生する必要がありますか? それのようには見えません。の実装テンプレートIServiceLocatorは、null 以外の事後条件の概念 を無視します。

  • 実装テンプレートも、 の代替構文としてIServiceLocator扱います。これは Liskov の違反 (基本型で宣言されていないサブタイプで例外をスローするため) と見なされますか? それとも、インターフェイスのメソッド シグネチャで宣言された例外ではなく、実際に実装に違いが必要でしょうか? 私が得ているのは、実装テンプレートが両方のインターフェースを正しく実装していると確信していますか? 呼び出しを try ブロックでラップし、例外がキャッチされたときに戻る というインターフェイスの意図をより適切に表現できますか?IServiceProvider.GetService(Type)IServiceLocator.GetInstance()ServiceLocatorImplBaseIServiceLocatorIServiceProviderGetInstancenull

  • 補遺:これに関連するもう 1 つの問題は、への対応IServiceLocator.GetAllInstances(Type)ですIServiceLocator.GetInstance(Type)。具体的には、任意の型 T について、 の実装はIServiceLocator.GetAllInstances(typeof(T))と同じ結果を返す必要がありIServiceLocator.GetInstance(typeof(IEnumerable<>).MakeGenericType(typeof(T))ますか? (これがIServiceProvider通信にどのように関係しているかは簡単にわかりますが、質問を単純にして、この場合は同じインターフェースの 2 つのメソッドのみを比較する方がよいと思います。)

4

2 に答える 2

11

IServiceProvider.GetServiceすでに指摘したように、との違いは、サービスが登録されていない場合、またはIServiceLocator.GetInstanceなんらかの理由で解決できない場合、IServiceProvider.GetService実装返される必要がありますが、一方で実装はその場合に例外をスローする必要があります (および決して返さない)。nullIServiceLocator.GetInstancenull

しかし、「すべき」という言葉の使用に注意してください。Common Service Locator プロジェクト(インターフェースを所有) に同梱されているすべての CSL アダプター (Windsor、Spring、Unity、StructureMap など) はIServiceLocatorインターフェースに準拠しておらずIServiceProvider、メソッドを呼び出すと例外がスローされますIServiceProvider.GetService

契約を破ることによって、CSL の設計者はIServiceProviderインターフェイスをまったく役に立たなくすることに成功しました。null を返すためにこれに頼ることができなくなりました。これは悪いことです。すごく悪い。コントラクトに準拠していると私が知っている唯一の CSL アダプターはSimple Injector アダプターですが、他のすべての実装が壊れているため、実装を安全に交換する方法がないため、この正しく実装されたアダプターでさえその時点では役に立ちません。

これはLiskovの違反と見なされますか

絶対。それらはインターフェイスの契約を破り、実装を互いに置き換えることはできません。

このスレッドに関するGlenn Blockのコメントからわかるように、設計者はこれについて知っています。

ここで失敗したようです。例外をスローするというアイデアは、私たち全員が同意した明示的な設計目標でした。IServiceProvider を実装することはより便利でしたが、これは見落とされていたようです。

CSL が更新されていないため、この欠陥は修正されていません。

于 2013-02-18T11:54:10.417 に答える
3

あなたが言及しなかった2つのデザインには違いがあると思います:


タイプserviceTypeのサービスオブジェクトがない場合は、IServiceProvider.GetServicenull 。


サービスインスタンスの解決中にエラーが発生した場合は、IServiceLocator.GetInstanceActivationExceptionがスローされます。

1つはデフォルトのケースを指定し、もう1つはエラーのケースを指定していることに注意することが重要です。それらが同じではないことは理にかなっています。

提供されたサンプルから、組み合わせが期待される実装であるように見えます。デフォルトではnull、エラーの場合はActivationExceptionでラップします。

編集:

具体的には、任意のタイプTについて、IServiceLocator.GetAllInstances(typeof(T))の実装はIServiceLocator.GetInstance(typeof(IEnumerable <>)。MakeGenericType(typeof(T))と同じ結果を返す必要がありますか?

typeof(IEnumerable<T>)よりコンパクトなフォームとして機能しませんか?さらに、タイプGetInstanceを求められたときになぜ何かを返すのでしょうか?IEnumerableそのように実装することもできますが、自動とは言いません。

于 2013-02-13T22:21:59.393 に答える