14

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?

vitidev
  • 860
  • 1
  • 8
  • 19
  • Your example doesn't make much sense. Why are you injecting multiple identical instances into the `ClassToResolve`? – Steven Jun 10 '11 at 09:23
  • They are not identical. They are identical only in the example. I simplified the example. In fact, this list of objects that inherit / implement from one base class / interface, or a list of differently configured objects. This is very similar to the pattern design "Director" where ClassToResolve = Director and CollectionItem=Strategy (like IRunnable) – vitidev Jun 11 '11 at 17:12
  • Are they all of the same interface or of different interfaces? What do you *actually* want to happen? – Matt Ellen Jun 11 '11 at 21:49
  • This is a very common use case. One object uses a list of other objects. But the problem is already solved. – vitidev Jun 12 '11 at 20:39

4 Answers4

46

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
  • 166,672
  • 24
  • 332
  • 435
0

@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>.

Community
  • 1
  • 1
Tohid
  • 6,175
  • 7
  • 51
  • 80
  • 1
    For code samples, could you replace the "var" with the concrete datatype(s)? I greatly appreciate this answer, but "var" within code samples ... doesn't helper the reader IMHO. Thanks. I'm guessing it is IEnumerable, but it would be nice to see what you have. – granadaCoder Aug 20 '19 at 17:36
-1

You should register you class in unity

container.RegisterType()

It's better to use interface

Navid Rahmani
  • 7,848
  • 9
  • 39
  • 57
  • Registration details are not present in the example. Because, this is the question - how to register this collection for auto-resolving it with Unity? – vitidev Jun 11 '11 at 17:18
-1

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
Navid Rahmani
  • 7,848
  • 9
  • 39
  • 57