0

I am trying to understand IoC and determine whether it is a good fit for this particular scenario. I have the following code:

public class List { ... }
public class Form { ... }

public interface IService { ... }

public class ListService : IService {
    public ListService(List list) { }
}

public class FormService : IService {
    public FormService(Form form) { }
}

class Program {
    static void Main(string[] args) {
        IUnityContainer container = new UnityContainer();
        container.RegisterType<IService, ListService>(new InjectionConstructor(typeof(List)));
        container.RegisterType<IService, FormService>(new InjectionConstructor(typeof(Form)));

        IService formService = container.Resolve<IService>(new DependencyOverride<Form>(new Form()));
        IService listService = container.Resolve<IService>(new DependencyOverride<List>(new List()));
    }
}

The code above obviously doesn't work because the second registration of IService overrides the first one. But the intent is to be able to resolve the right IService instance using its constructor dependency. I realized that it is not a typical IoC scenario but a hybrid factory / IoC and I want to know if unity can be wired to accommodate such scenario.

Edit for Conclusion:
The actual problem is more complex than the example above. The ServiceDefinition objects (List, Form) come from a WCF web service. From there, the system will construct the IService instance and a chain of other objects that eventually lead to a set of WPF view and view model. Some dependencies are clearly defined in the constructors, others uses interfaces as its constructor parameters.

My first approach was to use Named Registration combined with InjectionConstructor \ ResolvedParameter. But it quickly becomes quite convoluted. Per Randy's suggestion, I started looking into auto factory using Unity. Here is a related post on the technique. Here is my resulting code snippets

public class Form { }
public class FormService : IService{
    [InjectionConstructor]
    public FormService(Func<string, Form> func, string name):this(func(name)) { }
    public FormService(Form form) { }
}
public class FormDataViewModel {
    public FormDataViewModel(FormService svc) { }
}
public interface IService { }
class Program {
    static Form GetForm(string name) {
        //wcf call
        return new Form();
    }
    static void Main(string[] args) {
        IUnityContainer container = new UnityContainer();
        container.RegisterInstance<Func<string, Form>>(GetForm);
        container.RegisterType<IService, FormService>("form");
        FormDataViewModel vm = container.Resolve<FormDataViewModel>(new DependencyOverride<string>("/system/form/test"));
    }
}

The code above is in a sense a hybrid factory\IoC approach. Thanks goodness for the flexibility of Unity. Pure IoC would not be suitable in many of my scenarios.

Community
  • 1
  • 1
Rushui Guan
  • 3,023
  • 1
  • 24
  • 26
  • 1
    I don't think this is possible. Why not simply give each registration a name? Please note that you can do IOC without a container. This is called [Pure DI](http://blog.ploeh.dk/2014/06/10/pure-di/). – Yacoub Massad Feb 29 '16 at 21:48

1 Answers1

2

With Unity the only way (out of the box) to have more than one registration associated with an interface is to use a named registration.

In your scenario as presented (the actual scenario might be more complicated) it doesn't appear that that should be an issue. I would think you would know in some way what type of service you wanted (Form vs. List).

If the scenario is more complicated then you can almost always achieve what you want with a factory (factory is mentioned in the question so it seems to fit). See Automatic Factories for some factory examples.

Basically, all applicable instances of IService could be injected into the factory and the factory could determine at runtime (and based on whatever criteria is applicable) what is the appropriate IService instance to return. You can even inject Func<IService> instead of IService to defer object creation.

Randy Levy
  • 22,566
  • 4
  • 68
  • 94