Suppose I have an interface IStorage
and multiple implementations of it, e.g.:
class FileStorage : IStorage
{
public FileStorage(string filePath)
{
}
}
class HttpStorage : Storage
{
public HttpStorage(IHttpClient httpClient)
{
}
}
Now I have multiple classes that I want to register in my application and each of them needs a different IStorage
instance.
ClassA
(implementing and registered via IClassA
) need a singleton FileStorage
with "C:\Temp\foo.txt" as filePath
.ClassB
(implementing and registered via IClassB
) need a singleton FileStorage
with "C:\Temp\bar.txt" as filePath
.ClassC
(implementing and registered via IClassC
) need a singleton HttpStorage
with the registered singleton of IHttpClient
.How can I achieve the above without falling back to creating most of the dependency graph manually?
The primary question to ask every time you think you need this is: Do I violate the Liskov Substitution Principle. You are breaking the LSP in case the implementations aren't interchangeable for one another. If ClassA
breaks when you inject an HttpStorage
into it, you are breaking the LSP. In that case, you should give each implementation each own abstraction, such as IFileStorage
and IHttpStorage
.
My first impression is that you are not violating LSP. Simple Injector v3 contains a RegisterConditional
method that allows you to do conditional registrations. With Simple Injector v3.1 you can make the registration as follows:
Lifestyle transient = Lifestyle.Transient;
container.RegisterConditional(typeof(IStorage),
transient.CreateRegistration(() => new FileStorage(@"C:\Temp\foo.txt"), container),
c => c.Consumer.ImplementationType == typeof(ClassA));
container.RegisterConditional(typeof(IStorage),
transient.CreateRegistration(() => new FileStorage(@"C:\Temp\bar.txt"), container),
c => c.Consumer.ImplementationType == typeof(ClassB));
container.RegisterConditional(typeof(IStorage),
transient.CreateRegistration(() => new HttpStorage(new HttpClient()), container),
c => c.Consumer.ImplementationType == typeof(ClassC));
The RegisterConditional
overload that accepts an Registration
instance is new in v3.1.