Способ заполнения коллекции Unity
У меня есть два примера классов
class ClassToResolve
{
private List<CollectionItem> _coll;
public ClassToResolve(List<CollectionItem> coll)
{
_coll = coll;
}
}
class CollectionItem
{
//...
}
и мне нужно разрешить ClassToResolve
var classToResolve = new ClassToResolve(
new List<CollectionItem>()
{
new CollectionItem(),
new CollectionItem(),
new CollectionItem()
}
);
Теперь я разрешаю это способом
var classToResolve = new ClassToResolve(
new List<CollectionItem>()
{
unity.Resolve<CollectionItem>(),
unity.Resolve<CollectionItem>(),
unity.Resolve<CollectionItem>()
}
);
Есть ли способ разрешить ClassToResolve с Unity, используя динамическую регистрацию?
Ответы
Ответ 1
Unity поймет, что зависимости T[]
(array) - это список вещей (но не IEnumerable<T>
, а не List<T>
). Когда вы меняете конструктор ClassToResolve
, чтобы взять CollectionItem[]
вместо List<CollectionItem>
, вы можете настроить типы CollectionItem
следующим образом:
container.RegisterType<CollectionItem, CollectionItemA>("a");
container.RegisterType<CollectionItem, CollectionItemB>("b");
container.RegisterType<CollectionItem, CollectionItemC>("c");
container.RegisterType<CollectionItem, CollectionItemD>("d");
Трюк здесь - назвать все регистрации. Регистрация по умолчанию (безымянная) никогда не будет частью зависимостей последовательности в Unity.
Теперь вы можете разрешить ClassToResolve
без необходимости его регистрации:
container.Resolve<ClassToResolve>();
Если вы скорее добавите List<CollectionItem>
, вы можете добавить следующую регистрацию:
container.RegisterType<IList<CollectionItem>, CollectionItem[]>();
И для IEnumerable<CollectionItem>
вы можете добавить следующую строку:
container
.RegisterType<IEnumerable<CollectionItem>, CollectionItem[]>();
Ответ 2
Вы должны зарегистрировать свой класс в единстве
container.RegisterType()
Лучше использовать интерфейс
Ответ 3
Используйте этот
class ClassToResolve:IEnumerable<CollectionItem>
{
private List<CollectionItem> _coll;
public ClassToResolve(IUnityContainer container)
{
_coll = container.ResolveAll<CollectionItem>();
}
public IEnumerator<CollectionItem> GetEnumerator()
{
return _coll.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(CollectionItem)
{
this._coll.Add(CollectionItem);
}
}
now register you class
Ответ 4
@Steven ответ абсолютно прав, я просто хочу предложить другой способ решения проблемы.
Для лучшего и чистого кода стоит определить интерфейс для всех элементов коллекции.
public interface IMyClass
{
void DoSomething();
}
public abstract class MyClassBase : IMyClass
{
abstract void DoSomething();
// more code for the base class if you need it.
}
public class MyClassA : MyClassBase
{
void virtual DoSomething()
{
// implementation here
}
}
public class MyClassB : MyClassBase
{
void virtual DoSomething()
{
// implementation here
}
}
public class MyClassC : MyClassBase
{
void virtual DoSomething()
{
// implementation here
}
}
// etc.
Теперь регистрационный код для контейнера Unity будет намного проще:
container.RegisterTypes(
AllClasses.FromLoadedAssemblies().
Where(type => typeof(IMyClass).IsAssignableFrom(type)),
WithMappings.FromAllInterfaces,
WithName.TypeName,
WithLifetime.PerResolve);
container.RegisterType<IEnumerable<IMyClass>, IMyClass[]>();
и код решения одинаков:
var allOfMyClasses = container.ResolveAll<IMyClass>();
Я надеюсь, что Microsoft добавит поддержку IEnumerable<>
к следующей версии Unity, поэтому нам не нужно будет регистрировать IEnumerable<IMyClass>
.