1

I was just watching a Dependency Injection course on PluralSight that cleared up a couple of things for me. But despite the fact that it goes over a few layers, there was also no info about what exactly is the way to go when you just have to new up objects in your codde.

This is the last piece of the puzzle that I'm struggling to grasp. I know about Compisition Root and roughly how to use it. I know to avoid ServiceLocator and to avoid passing down the IoC container through all levels of the code by defining it as a ctor parameter in just about every class in the code base (which I both have seen side by side in a company that I worked for).

Let's consider the two examples below where I believe it is unpractical to impossible to hand in everything.

I can inject dependencies, but I can't possibly inject everything, it isn't called Object Injection after all, so the problem is how to dynamically create Doee objects inside of a loop:

public class MyClass
{
    private IVerifyer _verifyer;
    public MyClass(IVerifyer verifyer)
    {
        _verifyer = verifyer;
    }

    public IList<Doer> PrepareDoingSomething(IList<IDoees> doees)
    {
        var doers = new List<Doer>();
        foreach (var doee in doees)
        {
            if (!Verifyer.Verify(doee)) throw new Exception("Blablabla...");
            doers.Add(new Doer(doee));
        }
        return doers;
    }
}

Now in some "less dynamic" cases, the problem is that for some IO classes there is neither an interface nor an abstract base class available, which means that they are difficult deal with in test code, and also I wouldn't even know how to handle them with an IoC container, like the Process class:

public class Processor
{
    public Process ProcessSomething(IProcessee processee)
    {
        // do some pre-processing stuff here
        // static Start() returns a new Process instance
        return Process.Start("C:\MyApp.exe", $"-option {processee.Option1}");
    }
}

What I've done so far is to introduce in both cases an abstract factory class that I can inject and that gives me what I need when need it (i.e. dynamically in a loop). I have an implementation for production use. In test code I can either implement it or just mock it (since it's abstract). For the Process class I've introduced a proxy class with interface (I)ProcessProxy that passes through the calls to the actual Process class. I can also easily mock that if I need to. The two examples then turn into what I've listed below.

My question is, is that the right way to go in these two cases (which are my main concerns)? I know that I might trigger opinionated answers, but I'm just trying to figure out if that is the recommended way in the spirit of a clean and straight forward text book-like DependencyInjection and CompositionRoot implementation. If that's not the preferred way to go, then what is it?

Loop example after refactoring and DI enabled:

public class MyClass
{
    private IVerifyer _verifyer;
    private AbstractDoerFactory _doerFactory;
    public MyClass(IVerifyer verifyer, AbstractDoerFactory doerFactory)
    {
        _verifyer = verifyer;
        _doerFactory = doerFactory;
    }

    public IList<Doer> PrepareDoingSomething(IList<IDoees> doees)
    {
        var doers = new List<Doer>();
        foreach (var doee in doees)
        {
            if (!_verifyer.Verify(doee)) throw new Exception("Blablabla...");
            doers.Add(_doerFactory.GetNewDoer(doee));
        }
        return doers;
    }
}

Process example after refactoring and DI enabled:

public interface IProcessProxy : IDisposable
{
    TextReader StandardOutput { get; }
    TextReader StandardError { get; }
    int ExitCode { get; }
    Start(string fileName, string arguments);
    void Kill();
}

public class Processor
{
    private AbstractProcessProxyFactory _processProxyFactory;
    public Processor(AbstractProcessProxyFactory processProxyFactory)
    {
        _processProxyFactory = processProxyFactory;
    }

    public IProcessProxy ProcessSomething(IProcessee processee)
    {
        // do some pre-processing stuff here
        var processProxy = _processProxyFactory.GetProxyFactory();
        return processProxy.Start("C:\MyApp.exe", $"-option {processee.Option1}");
    }
}
DanDan
  • 595
  • 2
  • 8
  • 19

2 Answers2

1

DependencyInjection is an incredibly powerful tool for organizing complex polymorphic applications. I always look for opportunities to use it - but it's not ideal for handling every detail of your application.

Though it may have just been for example purposes, I wouldn't generally think to use DI to remove your dependence upon a standard system service like System.Process unless you had a very good reason for wanting to swap it out with a custom Process class. This would be a case of overusing Dependency Injection.

That said, when I have needed to dynamically construct instances of types well after the bootstrapping process I have found factories to be very useful. For the greatest flexibility, don't rely upon a single factory instance. Instead, provide the ability to register factories for different types independently.

public interface IFactory
{ 
    Type FactoryType;
    object CreateInstance(); 
}

namespace Generic {
    public interface IFactory<T> : IFactory
    {
        new T CreateInstance();
    }
}

public class DoThisFactory : IFactory<DoThis> { ... }
public class DoThatFactory : IFactory<DoThat> { ... }


public class MyClass
{
    // use property injection
    public DoThisFactory DoThisFactory { get; set; }       
    public DoThatFactory DoThatFactory { get; set; }

    private DoThis _doThis = null;
    private DoThat _doThat = null;

    public DoThis DoThis
    {
        get {
            if(_doThis == null) _doThis = DoThisFactory.CreateInstance();
            return _doThis;
        }
    }

    public DoThat DoThat
    {
        get {
            if(_doThat == null) _doThat = DoThatFactory.CreateInstance();
            return _doThat;
        }
    }
}

In the above, MyClass knows the different types of things he needs to do - the dependencies are explicit. This allows me to provide different (or the same) factory class to different types of IDoees.

If you don't know the specific implementation types that you will ultimately be working with, then you will need to inject an array of IFactory instances and use their FactoryType property to register them in a Dictionary for later lookup.

public class MyClass
{
    private Dictionary<Type, IFactory> _registerations = new Dictionary<Type, IFactory>();

    public MyClass(IFactory[] factories)
    {
        for(int i = 0; i < factories.Count -1; i++)
        {
            _registrations.Add(factories(i).FactoryType, factories);
        }
    }

    public IEnumeruable<IDoer> GetDoers(Type[] types)
    {
        List<IDoer> doers = new List<IDoer>();
        for(int i = 0; i < types.Count - 1; i++)
        {
            doers.Add(_registerations(types(i)).CreateInstance());
        }
        return doers;
    }
}
0

You can address the first issue with a factory, as outlined in the OP, although the question is whether you should. From the OP, it's not clear what IDoees is, but usually, objects that are passed as method arguments, or returned as return values, tend to be newables rather than injectables. The question is, then, whether you should even inject a factory. It might be more appropriate to simply new up Doer, as also shown in the OP.

When it comes to something like Process, while you can technically extract an interface from a concrete class, and then make an Adapter, this is generally not the best way to use Dependency Injection.

According to the Dependency Inversion Principle, abstractions shouldn't depend on details; details should depend on abstractions. What this normally means is that clients should define the abstraction they need, and then implementations should match that abstraction.

So, if a client has to run a process, rather than call it RunProcess, name it according to the problem it addresses. If, for example, you want to run a program called encode.exe, e.g. to encode some audio files, model the dependency according to that goal:

public class Foo
{
    private readonly IEncoder encoder;

    public Foo(IEncoder encoder)
    {
        this.encoder = encoder;
    }

    public Bar DoSomething(Baz baz)
    {
        // Maybe do something else first...

        this.encoder.Encode(/*...*/);

        // Maybe do something else after...
    }
}

You can then implement IEncoder using the Process API, if you need to:

public class Encoder : IEncoder
{
    public void Encode(/*...*/)
    {
        // Start encode.exe here...
    }
}

If the operation is long-running, you can return a Task from Encode, instead of void; if you need to be able to cancel the task, pass a CancellationToken as a method argument to the Encode method; and so on. Model the dependency around the requirements of the client(s), not the implementation details.

Mark Seemann
  • 209,566
  • 41
  • 390
  • 671