17

.Net IoC コンテナーが、単一のインターフェイスに対して複数の実装を簡単にサポートできない理由を知りたいです。私が間違っているかもしれませんが、私が見た限りでは、Ninject のようなフレームワークは、注釈を使用してこの機能を部分的にサポートしています (どのように? )。Windsor や単純なインジェクターなどの他のフレームワークには、このシナリオをサポートする簡単なメカニズムはないと思います。

これが多くのフレームワークでサポートされていない理由はありますか? 私の知る限り、インターフェイスを使用する最も重要な理由の 1 つは、疎結合を実現することです。疎結合を改善するように設計されたフレームワークが、単一のインターフェースに対して複数の実装をスムーズにサポートしない場合、私にはその理由がわかりません!

PSもちろん、実行時に解決の問題が発生し、コンテナがどの実装を選択するか混乱することは理解していますが、それは設計で考慮しなければならないことですよね?

4

7 に答える 7

10

Unityには同じ機能があります

名前付き依存関係を登録する

    var container = new UnityContainer();
    container.RegisterType<IConnector, Connector>("TestConnector");

名前で解決

    container.Resolve<IConnector>("TestConnector");

同じアプローチ

    [Dependency("TestConnector")]
    public IConnector Connector { get; set; }

ウィンザーも同じ

class Program
{
    static void Main(string[] args)
    {
        var container = new WindsorContainer()
            .Register(Component.For<IConnector>().ImplementedBy<ConnectorA>().Named("ConnectorA"))
            .Register(Component.For<IConnector>().ImplementedBy<ConnectorB>().Named("ConnectorB"));

        var connectorA = container.Resolve<IConnector>("ConnectorA");
        Console.WriteLine("Connector type: {0}", connectorA.GetType());
        var connectorB = container.Resolve<IConnector>("ConnectorB");
        Console.WriteLine("Connector type: {0}", connectorB.GetType());
        Console.ReadKey();
    }
}

public interface IConnector
{
}

public class ConnectorA : IConnector
{

}

public class ConnectorB : IConnector
{

}
于 2012-07-29T10:29:34.233 に答える
8

設定より規約、特に規約ベースの依存性注入コンテキストベースの依存性注入を検討することをお勧めします。すべてではないにしても、ほとんどの IC が両方のアプローチをサポートしています。複数の実装が 1 つのインターフェイスにバインドされている場合、さまざまな IoC ライブラリを使用した多くの興味深いサンプルと、それがどれほど役立つかを見つけることができます。

たとえば、は、1 つのインターフェースの複数の実装のバインドをサポートしています:コンテキストまたは属性、名前などに依存します

コンテキスト別

実装時の次のスニペット バインドは、ターゲット タイプに自動的に依存します。

Bind<IWarrior>().To<Samurai>().WhenInjectedInto(typeof(OnLandAttack));
Bind<IWarrior>().To<SpecialNinja>().WhenInjectedInto(typeof(AmphibiousAttack));

名前で

構成が XML またはデータベースである場合に非常に役立ちます。InNamedScope以下も考慮してください。

Bind<IWeapon>().To<Shuriken>().Named("Strong");
Bind<IWeapon>().To<Dagger>().Named("Weak");

慣例により

プロジェクトのさまざまな部分でさまざまな依存関係構成を使用します。

于 2012-07-29T16:47:56.420 に答える
6

あなたの前提は間違っています。

Windsor は、同じサービスの複数の実装の登録を喜んで受け入れます。GSerjo が言及した名前付きコンポーネントの解決サポートに加えて、Windsor では (デフォルトで)、最初に登録された実装が優先されますがIsDefault()、別の実装を登録するときにメソッドを使用してこれをオーバーライドできます。詳細については、 http://docs.castleproject.org/Windsor.Registering-components-one-by-one.ashxを参照してください。

複数の実装からの選択をより詳細に制御したい場合は、そのために IHandlerSelector 実装を作成できます。詳細については、 http://stw.castleproject.org/Windsor.Handler-Selectors.ashxを参照してください。

于 2012-07-30T00:09:53.663 に答える
2

私のコンテナ Griffin.Container はそれをサポートしています。

registrar.RegisterConcrete<OneImplementation>();
registrar.RegisterConcrete<AnotherImplementation>();

そしてフェッチするには:

var services = container.Resolve<ITheService>();

ただし、1 つの特定の実装を取得することはできません。設計上の決定です。特定の実装を取得する必要がある場合は、コンテナにファクトリを登録する方がはるかに優れています。詳細については、こちらのベスト プラクティス セクションを参照してください。

Griffin.Container は github にあります: https://github.com/jgauffin/griffin.container

于 2012-07-29T10:35:46.063 に答える
1

StructureMapは、次の機能を提供します。

For<IMyInterface>().Add<MyInterfaceImpl1>().Named("MyInterfaceImpl1");
For<IUsingInterface>().Add<UsingInterfaceImpl>().Ctor<IMyInterface>().Is(i => i.GetInstance<IMyInterface>("MyInterfaceImpl1"));
于 2012-07-29T10:11:22.597 に答える
1

これが必要だと思うときの具体的な例を提供していないため、質問は少しあいまいです。ほとんどの場合、アプリケーションまたは設計に問題があるか、DI のベスト プラクティスに従っていません。

すべてのコンテナを使用すると、複数の依存関係を同じインターフェイスに登録できます。IEnumerable<ThatInterface>、たとえ複数のインスタンスを深くサポートしていなくても。ただし、サービスのリストを他のサービスに挿入するのは設計上の臭いであり、このリストをコンポジットの背後に隠す方がよいでしょう。これにより、抽象化の背後に複数の実装があるという事実が隠され、アプリケーション内の 1 つの場所を変更するだけで、これらの複数の実装の使用方法を簡単に変更できます。ラップされた実装を処理するデフォルトの方法は 1 つもないため、IoC フレームワークがコンポジットの生成をサポートしているとは思えません。この Composite は自分で作成する必要があります。ただし、このようなコンポジットを作成するのは非常に単純であるため、フレームワークにそのような機能を持たないことは正当化されます。

複数の実装を持ちたいが、何らかの構成に基づいて常に 1 つを返す必要がある場合は、常にこれを行う方法があります。ほとんどのコンテナーでは、XML 構成ファイルでこれらの依存関係を構成できます。ただし、コンテナーにそのような機能が含まれていない場合でも、構成ファイルからこの値を手動で読み取り、適切な型をコンテナーに登録するのは非常に簡単です。

本番用の特定のインターフェースの 1 つの実装と単体テスト用の別の実装がある場合は、本番用の実装のみをコンテナーに登録する必要があります。単体テストには DI コンテナーを含めないようにする必要があります。テスト対象のクラスを手動で作成し、コンストラクターに偽の依存関係を挿入する必要がありますnew。DI コンテナーを使用すると、テストが汚染され、複雑になります。これをやってのけるには、コンストラクター注入パターンの周りにそのような型を設計する必要があります。依存関係を取得するために、テスト中のサービス内でコンテナー (またはコンテナー上の他のファサード) を呼び出さないでください。

于 2012-07-30T16:56:17.313 に答える