Как настроить Unity для вставки массива для IEnumerable - PullRequest
4 голосов
/ 15 декабря 2011

У меня есть класс, который принимает параметр конструктора IEnumerable, который я хочу разрешить с помощью Unity и внедрить массив объектов.Эти простые классы иллюстрируют проблему.

public interface IThing
{
    int Value { get; }
}

public class SimpleThing : IThing
{
    public SimpleThing()
    {
        this.Value = 1;
    }

    public int Value { get; private set; }
}

public class CompositeThing : IThing
{
    public CompositeThing(IEnumerable<IThing> otherThings)
    {
        this.Value = otherThings.Count();
    }

    public int Value { get; private set; }
}

Скажем, я хочу добавить четыре SimpleThing в CompositeThing.Я пробовал несколько вариантов следующей конфигурации Unity.

<alias alias="IThing" type="TestConsoleApplication.IThing, TestConsoleApplication" />
<alias alias="SimpleThing" type="TestConsoleApplication.SimpleThing, TestConsoleApplication" />
<alias alias="CompositeThing" type="TestConsoleApplication.CompositeThing, TestConsoleApplication" />

<container>

  <register type="IThing" mapTo="SimpleThing" name="SimpleThing" />
  <register type="IThing" mapTo="CompositeThing" name="CompositeThing">
    <constructor>
      <param name="otherThings">
        <array>
          <dependency type="SimpleThing"/>
          <dependency type="SimpleThing"/>
          <dependency type="SimpleThing"/>
          <dependency type="SimpleThing"/>
        </array>
      </param>
    </constructor>
  </register>

</container>

Однако я получаю сообщение об ошибке Конфигурация настроена на внедрение массива, но тип IEnumerable`1 не является типом массива. Если я изменяю параметр конструктора на IThing[], он работает, но я не хочу этого делать.Что мне нужно сделать с моей конфигурацией Unity, чтобы заставить это работать?

Ответы [ 3 ]

3 голосов
/ 16 декабря 2011

Вот одно решение, которое я нашел, но оно немного наф.Вам нужен класс-обертка, чтобы помочь Unity распознать, что массив IEnumerable.

public class ArrayWrapper<T> : IEnumerable<T>
{
    public ArrayWrapper(T[] things)
    {
        this.things = things;
    }

    private IEnumerable<T> things;

    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return this.things.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.things.GetEnumerator();
    }
}

Затем вы можете настроить Unity для внедрения одного из них, используя идею EnumberableThing Этана.

<alias alias="IThing" type="TestConsoleApplication.IThing, TestConsoleApplication" />
<alias alias="SimpleThing" type="TestConsoleApplication.SimpleThing, TestConsoleApplication" />
<alias alias="CompositeThing" type="TestConsoleApplication.CompositeThing, TestConsoleApplication" />
<alias alias="EnumerableThing" type="System.Collections.Generic.IEnumerable`1[[TestConsoleApplication.IThing, TestConsoleApplication]], mscorlib"/>
<alias alias="ThingArrayWrapper" type="TestConsoleApplication.ArrayWrapper`1[[TestConsoleApplication.IThing, TestConsoleApplication]], TestConsoleApplication"/>

<container>
  <register type="EnumerableThing" mapTo="ThingArrayWrapper">
    <constructor>
      <param name="things">
        <array>
          <dependency type="SimpleThing"/>
          <dependency type="SimpleThing"/>
          <dependency type="SimpleThing"/>
          <dependency type="SimpleThing"/>
        </array>
      </param>
    </constructor>
  </register>

  <register type="IThing" mapTo="SimpleThing" name="SimpleThing" />

  <register type="IThing" mapTo="CompositeThing" name="CompositeThing">
    <constructor>
      <param name="otherThings" dependencyType="EnumerableThing" />
    </constructor>
  </register>
</container>

Как я уже сказал, немного нахально и неловко, когда вы хотите еще один CompositeThing с тремя, пятью, шестью вещами и т. Д.

Конечно, Unity долженбыть в состоянии распознать, что массив IEnumberable и внедрить его?

2 голосов
/ 13 января 2016

На самом деле Unity понимает массивы.Принятое решение будет отлично работать, но если вам не нужна оболочка, и если вы хотите получить все зарегистрированные реализации, это так же просто, как:

public class CompositeThing : IThing
{
    public CompositeThing(IThing[] otherThings)
    {
        this.Value = otherThings.Count();
    }

    public int Value { get; private set; }
}

Недостатком является то, что оно, вероятно, также вернетэкземпляр, если он сам, так как он реализует IThing.

Подобный вопрос здесь: Как внедрить IEnumerable с использованием контейнера IOC Microsoft Unity

Просто убедитесь, что вы зарегистрировали реализации с определеннымname, как таковое:

container.RegisterType<IThing, FooThing>("Foo");
container.RegisterType<IThing, BarThing>("Bar");

Я не знаю синтаксис для XML, но я уверен, что вы также можете реализовать его там.

0 голосов
/ 16 декабря 2011

По умолчанию не поддерживается IEnumerable<T> зависимость для конфигурации Unity. Единственная альтернатива, использующая существующую конфигурацию единства для достижения вашей цели, состоит в том, чтобы отобразить IEnumerable<T> в T [] следующим образом.

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
 <alias alias="IThing" type="TestConsoleApplication.IThing, TestConsoleApplication" />
 <alias alias="SimpleThing" type="TestConsoleApplication.SimpleThing, TestConsoleApplication" />
 <alias alias="CompositeThing" type="TestConsoleApplication.CompositeThing, TestConsoleApplication" />
 <alias alias="EnumerableThing" type="System.Collections.Generic.IEnumerable`1[[TestConsoleApplication.IThing, TestConsoleApplication]], mscorlib"/>
 <alias alias="ThingArray" type="TestConsoleApplication.IThing[], TestConsoleApplication"/>

 <container>
   <register type="EnumerableThing" mapTo="ThingArray"/>
   <register type="IThing" mapTo="SimpleThing" name="SimpleThing" />
   <register type="IThing" mapTo="CompositeThing">
    <constructor>
      <param name="otherThings" dependencyType="EnumerableThing"/>
    </constructor>
  </register>
</container>

C # код:

 IUnityContainer container = new UnityContainer();
 container.LoadConfiguration();
 IThing thing = container.Resolve<CompositeThing>();
 Console.WriteLine(thing.Value);

Если вы не хотите таким образом, я думаю, вы можете расширить Unity Configuration System для поддержки IEnumerable<T> разрешения зависимостей, внедрив новый EnumerableElement, унаследованный ParameterValueElement.

...