Your question contains an example of the Service Locator anti-pattern:
public class UsesMyService
{
private readonly IMyService _service;
public UsesMyService()
{
_service = SomeClassWithContainer.UnityContainer.Resolve<IMyService>();
}
}
This is fundamentally different than the Dependency Injection pattern because of the direction the information flows: in the above example, you reach out and ask for the service, whereas in the example below, you are handed the service:
public class UsesMyService
{
private readonly IMyService _service;
public UsesMyService(IMyService service)
{
_service = service;
}
}
This pattern, known as constructor injection, decouples the UsesMyService
class from details about the surrounding infrastructure. Now, anyone with an implementation of IMyService
can create instances of UsesMyService
without having to know to configure a central static location.
How would they even know what to configure? They would either need the source code or some documentation telling them that the class depends on IMyService
. The constructor parameter cleanly expresses that requirement to consumers without any external reference.
If you follow this pattern throughout your libraries, you bubble the responsibility of assembling the objects all the way to the outermost layer, known as the Composition Root. This single location, usually the top-level application class, is the only place with references to all of the libraries you are using. That is where the container lives, and no other class in your entire solution needs to reference it.