Question

I am fairly new to Dependency Injection, and I wrote a great little app that worked exactly like Mark Seemann told me it would and the world was great. I even added some extra complexity to it just to see if I could handle that using DI. And I could, happy days.

Then I took it to a real world application and spent a long time scratching my head. Mark tells me that I am not allowed to use the 'new' keyword to instantiate objects, and I should instead let the IoC do this for me.

However, say that I have a repository and I want it to be able to return me a list of things, thusly:

public interface IThingRepository
{
 public IEnumerable<IThing> GetThings();
}

Surely at least one implementation of this interface will have to instantiate some Thing's? And it doesn't seem so bad being allowing ThingRepository to new up some Things as they are related anyway.

I could instead pass round a POCO instead, but at some point I'm going to have to convert the POCO in to a business object, which would require me to new something up.

This situation seems to occur every time I want a number of things which is not knowable in the Composition Root (ie we only find out this information later - for example when querying the database).

Does anyone know what the best practice is in these kinds of situations?

Était-ce utile?

La solution

In addition to Steven's answer, I think it is ok for a specific factory to new up it's specific matching-implementation that it was created for.

Update

Also, check this answer, specifically the comments, which say something about new-ing up instances.

Example:

public interface IContext {
    T GetById<T>(int id);
}

public interface IContextFactory {
    IContext Create();
}

public class EntityContext : DbContext, IContext {
    public T GetById<T>(int id) {
        var entity = ...;   // Retrieve from db
        return entity;
    }
}

public class EntityContextFactory : IContextFactory {
    public IContext Create() {
        // I think this is ok, since the factory was specifically created
        // to return the matching implementation of IContext.
        return new EntityContext(); 
    }
}

Autres conseils

Mark tells me that I am not allowed to use the 'new' keyword to instantiate objects

That's not what Mark Seemann tells you, or what he means. You must make the clear separation between services (controlled by your composition root) at one side and primitives, entities, DTOs, view models and messages on the other side. Services are injectables and all other types are newables. You should only prevent using new on service types. It would be silly to prevent newing up strings for instance.

Since in your example the service is a repository, it seems reasonable to assume that the repository returns domain objects. Domain objects are newables and there's no reason not to new them manually.

Thanks for the answers everybody, they led me to the following conclusions.

Mark makes a distinction between stable and unstable dependencies in the book I am reading ( "Dependency injection in .NET"). Stable dependencies (eg Strings) can be created at will. Unstable dependencies should be moved behind a seam / interface.

A dependency is anything that is in a different assembly from the one that we are writing.

An unstable dependency is any of the following

  • It requires a run time environment to be set up such as a database, web server, maybe even the file system (otherwise it won't be extensible or testable, and it means we couldn't do late binding if we wanted to)
  • It doesn't exist yet (otherwise we can't do parallel development)
  • It requires something that isn't installed on all machines (otherwise it can cause test difficulties)
  • It contains non deterministic behaviour (otherwise impossible to test well)

So this is all well and good.

However, I often hide things behind seams within the same assembly. I find this extremely helpful for testing. For example if I am doing a complex calculation it is impossible to test the entire calculation well in one go. If I split the calculation up into lots of smaller classes and hide these behind seams, then I can easily inject any arbirtary intermediate results into a calculating class.

So, having had a good old think about it, these are my conclusions:

  • It is always OK to create a stable dependency
  • You should never create unstable dependencies directly
  • It can be useful to use seams within an assembly, particularly to break up big classes and make them more easily testable.

And in answer to my original question, it is ok to instatiate a concrete object from a concrete factory.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top