4

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

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, чтобы заставить это работать?

+0

возможно дубликат [постановляющей IEnumerable с Unity] (http://stackoverflow.com/questions/1961549/resolving-ienumerablet-with-unity) –

+3

Я не думаю, что это дубликат, потому что речь идет о программном регистрации тогда как я использую конфигурационный файл. – batwad

ответ

3

Вот одно из решений, которое я нашел, но это немного наглый. Вам нужен класс-оболочка, чтобы помочь 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 с три, пять, шесть, и т.д.

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

0

Нет поддержки по умолчанию для зависимостей 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 для поддержки IEnumerable<T> зависимость решения, путем внедрения нового EnumerableElement Наследовать ParameterValueElement.

+0

Вы можете добавить поддержку IEnumerable , ICollection и IList через расширение контейнера, которое можно найти в проекте [TecX] (http://tecx.codeplex.com). Исходный код для _CollectionResolutionExtension_ находится внутри проекта TecX.Unity. –

+0

Звучит очень хорошо, спасибо за обмен :) –

+0

Изменив определение 'ThingArray' на' SimpleThing [] 'Мне удалось получить пример работы и ввести пустой массив, но как я могу определить' EnumerableThing', чтобы содержать четыре ' SimpleThing'? – batwad

1

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

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

    public int Value { get; private set; } 
} 

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

вопрос здесь похож: How to inject IEnumerable using Microsoft Unity IOC container

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

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

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