4

次のシナリオがあるとします。

System.Linq を使用します。
NUnit.Framework の使用;
パブリック インターフェイス IChannel {
   void Write(double 値);
}

public class Channel: IChannel {
   プライベート readonly int channelNumber;
   public Channel(int channelNumber) {
      Requires.That(channelNumber >= 0, "channelNumber >= 0");
      this.channelNumber = channelNumber;
   }
   プライベート int 呼び出し。
   public void Write(double value) {
      System.Console.WriteLine("{0} がチャネル {1} [#{2}] に書き込みました", value.ToString(), channelNumber, ++calls);
   }
}

パブリック インターフェイス IService {
   void Do();
}

public class ServicePiGreek: IService {
   プライベートな読み取り専用 IChannel チャネル。
   public ServicePiGreek(IChannel チャネル) {
      Requires.IsNotNull(チャンネル、「チャンネル」);
      this.channel = チャネル;
   }
   public void Do() {
      channel.Write(3.14);
   }
}
public class ServiceEuler: IService {
   プライベートな読み取り専用 IChannel チャネル。
   public ServiceEuler(IChannel チャネル) {
      Requires.IsNotNull(チャンネル、「チャンネル」);
      this.channel = チャネル;
   }
   public void Do() {
      channel.Write(2.71);
   }
}

したがって、チャネル 0 と 1 を持つ 2 つの ServicePiGreek と、チャネル 0 を持つ ServiceEuler を作成します。

[テストフィクスチャ]
公開クラス テスト {
   [テスト]public void without_simpleinjector() {
      var ch0 = 新しいチャンネル (0);
      var s0 = 新しい ServicePiGreek(ch0);
      var s1 = new ServicePiGreek(新しいチャンネル(1));
      var s2 = 新しい ServiceEuler(ch0);
      s0.Do();
      s1.Do();
      s2.Do();
   }

私はこれについて考えました:

   [テスト] public void with_simpleinjector() {
      SimpleInjector.Container コンテナー = 新しい SimpleInjector.Container();
      container.RegisterAll(新しいチャンネル(0)、新しいチャンネル(1));
      container.RegisterAll(GetAllServices(コンテナ));

      foreach (container.GetAllInstances() 内の var サービス) {
         サービス.Do();
      }
   }

   プライベート System.Collections.Generic.IEnumerable GetAllServices(SimpleInjector.Container コンテナー) {
      yield return new ServicePiGreek(container.GetAllInstances().ElementAt(1));
      yield return new ServicePiGreek(container.GetAllInstances().ElementAt(0));
      yield return new ServiceEuler(container.GetAllInstances().ElementAt(0));
   }

これを達成する方法について誰かがより良いアイデアを持っていますか?

4

1 に答える 1

4

IChannel同じリストに同じ実装が複数回(一時的に)あり、インターフェイスの異なる実装で埋める必要があるため、ユースケースは通常のものではありません。

あなたのデザインを調べることはできませんが、現在タイプを登録している方法は理にかなっています。反復時にコンテナーにコールバックする動的 IEnumerable を登録します。返されたElementAtコレクションがIList<T>.

コードを読みやすくするために、次のことを行うことができます。

private IEnumerable<IService> GetAllServices(Container container) {
  var channels = container.GetAllInstances<IChannel>();
  yield return new ServicePiGreek(channels.ElementAt(0));
  yield return new ServicePiGreek(channels.ElementAt(1));
  yield return new ServiceEuler(channels.ElementAt(0));

}

または、IService実装がシングルトンになる可能性がある場合は、次のことができます。

var container = new SimpleInjector.Container();

var blueChannel = new Channel(0);
var redChannel = new Channel(1);

container.RegisterAll<IService>(
    new ServicePiGreek(blueChannel),
    new ServicePiGreek(redChannel),
    new ServiceEuler(blueChannel),  
);

foreach (var service in container.GetAllInstances<IService>()) {
    service.Do();
}

要素をインデックスでリクエストする代わりに、ファクトリの背後でこれを抽象化できます。たとえば、次のようになります。

interface IChannelProvider
{
    IChannel GetBlueChannel();
    IChannel GetRedChannel();
}

ただし、これが機能するかどうかはシナリオによって異なります。

于 2013-05-10T14:45:58.890 に答える