Way to fill collection with Unity
I have two example classes
class ClassToResolve
{
private List<CollectionItem> _coll;
public ClassToResolve(List<CollectionItem> coll)
{
_coll = coll;
}
}
class CollectionItem
{
//...
}
and I need to resolve ClassToResolve
var classToResolve = new ClassToResolve(
new List<CollectionItem>()
{
new CollectionItem(),
new CollectionItem(),
new CollectionItem()
}
);
Now I resolve it in a way
var classToResolve = new ClassToResolve(
new List<CollectionItem>()
{
unity.Resolve<CollectionItem>(),
开发者_运维技巧 unity.Resolve<CollectionItem>(),
unity.Resolve<CollectionItem>()
}
);
Is there a way to resolve ClassToResolve with Unity using dynamic registration?
Unity will understand that T[]
(array) dependencies are a list of things (but not IEnumerable<T>
, nor List<T>
). When you change the constructor of ClassToResolve
to take an CollectionItem[]
instead of a List<CollectionItem>
you can configure your CollectionItem
types as follows:
container.RegisterType<CollectionItem, CollectionItemA>("a");
container.RegisterType<CollectionItem, CollectionItemB>("b");
container.RegisterType<CollectionItem, CollectionItemC>("c");
container.RegisterType<CollectionItem, CollectionItemD>("d");
The trick here is to name all the registrations. A default (nameless) registration will never be part of a sequence dependency in Unity.
Now you can resolve ClassToResolve
without the need to register it:
container.Resolve<ClassToResolve>();
If you rather inject List<CollectionItem>
you can add the following registration:
container.RegisterType<IList<CollectionItem>, CollectionItem[]>();
And for IEnumerable<CollectionItem>
you can add the following line:
container
.RegisterType<IEnumerable<CollectionItem>, CollectionItem[]>();
@Steven's answer is perfectly correct, I just want to suggest another way to tackle the issue.
For the sake of a better and cleaner code, it is worth it to define an interface for all the collection items.
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.
Now the registration code for Unity container would be much more easier:
container.RegisterTypes(
AllClasses.FromLoadedAssemblies().
Where(type => typeof(IMyClass).IsAssignableFrom(type)),
WithMappings.FromAllInterfaces,
WithName.TypeName,
WithLifetime.PerResolve);
container.RegisterType<IEnumerable<IMyClass>, IMyClass[]>();
and the resolve code is the same:
var allOfMyClasses = container.ResolveAll<IMyClass>();
I hope Microsoft add IEnumerable<>
support to the next version of Unity so we won't need to register IEnumerable<IMyClass>
.
You should register you class in unity
container.RegisterType()
It's better to use interface
Use this
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
精彩评论