Dependency Injection - new instance required in several of a classes methods
Most of the answers here so far suggest that you change the injected dependency type to some sort of Abstract Factory (a Func<T>
is also an Abstract Factory) to address the issue. However, if you do that it would be a leaky abstraction because you would let the knowledge of a particular implementation determine the design of the consumer. This violates the Liskov Substitution Principle.
A better option is to keep MyService as it is, and then create a wrapper for IDependency that addresses the particular lifetime issue:
public class TransientDependencyWrapper : IDependency
{
public void DoSomething()
{
new MyStatefulDependency().DoSomething();
}
}
Inject that into MyService instead of directly injecting the original implementation (MyStatefulDependency).
If you want to abstract away the creation of the dependency, you can always inject an Abstract Factory at this level.
Dependency injection if a class needs to create multiple instances of another class when required in a method
Like dkatzel said, use a factory
. This is the way I go about it. If you were creating instances of say, BaseViewModel
:
public interface IViewModelFactory {
T Create<T>() where T : BaseViewModel;
}
public class ViewModelFactory : IViewModelFactory {
private readonly Dictionary<Type, Func<BaseViewModel>> _factories;
public ViewModelFactory(Dictionary<Type, Func<BaseViewModel>> factories) {
_factories = factories;
}
public T Create<T>() where T : BaseViewModel {
return _factories[typeof (T)]() as T;
}
}
So now we have an injectable factory that can be configured to create and return anything that implements BaseViewModel
.
In IoC we need to configure the types to return so imagine these view models (and note the dependency in the second view model):
public abstract class BaseViewModel {
// ...
}
public class FirstViewModel : BaseViewModel {
// ...
}
public class SecondViewModel : BaseViewModel {
private readonly ISomeDependency _injectedDependency;
public SeoncdViewModel(ISomeDependency dependency) {
_injectedDependency = dependency;
}
}
And (using Autofac) we configure it like this:
var builder = new ContainerBuilder();
builder.Register(b => {
var factories = new Dictionary<Type, Func<BaseViewModel>> {
{ typeof (FirstViewModel), () => new FirstViewModel() },
{ typeof (SecondViewModel), () => new SecondViewModel(b.Resolve<ISomeDependency>()) },
};
return new ViewModelFactory(factories);
}).As<IViewModelFactory>();
And now we can inject IViewModelFactory
and create instances of FirstViewModel
or SecondViewModel
:
public class SomeClass {
public readonly IViewModelFactory _factory;
public SomeClass(IViewModelFactory factory) {
_factory = factory;
var secondViewModel = _factory.Create<SecondViewModel>();
}
}
The nice part is that IoC handles all of the dependencies. SomeClass
just knows that it has a thing that can create a SecondViewModel
so SomeClass
doesn't need to know about SecondViewModels
dependencies.
Java EE CDI - obtaining a new instance of a class each time a method is called
Since what you desire is having a new instance of Dependency
, each time the method is called, I think what you need is an instance of Provider
that is (javax.inject.Provider<T>
) injected in your class/bean
.
Inject the provider to your current class:
@Inject Provider<DesiredBean> provider;
Then, in your method doStuff()
obtain the new instance:
DesiredBean desiredBean = provider.get();
This should get you going.
Dependency injection in multiple classes?
Yes, in this case you will create two instances of the component and of the module; thus, you will have two instances of the ObjClass, even though you've marked it as @Singleton. The problem is that scoped dependencies are singletons only in scope of a component object. It means that creating new component instances will lead to creating new dependencies instances. Look at the example:
Let's extend your void runner method:
void runner(){
DaggerInjectorComponent comp = DaggerInjectorComponent.builder....
comp.InjectorModule(new InjectorModule(...));
comp.inject(this) //HERE YOU CREATE AND INJECT YOUR DEPENDENCY
comp.inject(this) // HERE NOTHING WILL HAPPEN, AS DEPENDENCY IS CACHED
}
After running this code your instance is not recreated because it's marked as @Singleton, therefore it's a scoped dependency, so Dagger will know that for this instance of component it's required to initialize this object only once.
But if we recreate or component, this logic will stop working:
void runner(){
DaggerInjectorComponent comp = DaggerInjectorComponent.builder....
comp.InjectorModule(new InjectorModule(...));
comp.inject(this) //HERE YOU CREATE AND INJECT YOUR DEPENDENCY
comp = null
comp = DaggerInjectorComponent.builder.... // component is recreated
comp.InjectorModule(new InjectorModule(...));
comp.inject(this) // HERE YOUR DEPENDECY IS REINITIALIZED, COMPLETELY NEW OBJECT
}
As it was said before, all singletons in dagger are tied to their component instance. If you create a new instance, it will have it's own singletons. But for you as for the client of this functionality, you'll end up with different instances.
To fix it, you mustn't recreate your component. For example, you can store it somewhere in the place which for sure won't be recreated.
I hope it helped.
Should we still create instances if we want to take advantage of dependency injection?
The idea behind Dependency Injection is to avoid creating instances inside a class, but how to deal with this scenario?
That's not at all the point. One of the central points of DI is to enable loose coupling to Volatile Dependencies. Not all types a class depends on are volatile. Some are stable and there is no need to prevent creating stable dependencies from within a class. Chapter one of both Dependency Injection in .NET (by Mark Seemann) and its successor Dependency Injection Principles, Practices, and Patterns (by Mark and I) have a detailed description of what Volatile Dependencies and Stable Dependencies are and how they differ.
The main question you should ask is whether any of the types that WebClientService
depend on are Volatile Dependencies or not. The answer depends on your particular context, and you should be able to figure this out after (re)reading chapter 1. This chapter can be read online freely.
With DI, create a new instance every time the interface is used
This is not something that your DI Container can (or arguably should) solve for you. It's the DI Container's job to inject a dependency into a consumer. After that, the consumer stores the dependency in a private field, which means that -as long as the consumer lives- it will reuse that same dependency.
Fortunately, you are programming to interfaces, which means you can solve this problem using a special Proxy implementation that can be placed inside your application's Composition Root. For instance:
public class AlwaysNewNumberWriter : INumberWriter
{
public void Write() => new NumberWriter().Write();
}
Instead of registering NumberWriter
in the container, you can now register AlwaysNewNumberWriter
as follows:
services.AddSingleton<INumberWriter, AlwaysNewNumberWriter>();
This solution, however, might be too simplistic, because NumberWriter
might have dependencies of its own, that need to be resolved from the DI Container. In that case, you'll need a slightly more complex solution:
public class DispatchingNumberWriter : INumberWriter
where TNumberWriter : INumberWriter
{
private readonly Func<INumberWriter> factory;
public DispatchingNumberWriter(Func<INumberWriter> factory)
{
this.factory = factory;
}
public void Write() => this.factory.Invoke().Write();
}
This DispatchingNumberWriter
accepts a Func<INumberWriter>
factory delegate, which it calls every time its Write
method is called. This allows you to, instead of injecting the NumberWriter
implementation into consumers, inject this DispatchingNumberWriter
.
The following code demonstrates how to wire everything together:
services.AddTransient<NumberWriter>();
services.AddScoped<INumberWriter>(c =>
new DispatchingNumberWriter(
() => c.GetRequiredService<NumberWriter>()));
Please note the following about this last snippet:
- The
DispatchingNumberWriter
is supplied with a delegate that calls back into the DI Container to resolve a newNumberWriter
. This allows theNumberWriter
to be created by the DI Container, which might construct the type using Auto-Wiring, i.e. automatically detecting and injecting its dependencies. - Because
NumberWriter
is created by the DI Container, it is registered asTransient
; otherwise instances might still be reused. - The
DispatchingNumberWriter
is registered as Scoped, which the safest lifestyle for this class, because:- Registering
DispatchingNumberWriter
asSingleton
will cause it'sc
parameter and the call to itsGetRequiredService
method to run in the container's global scope. This can cause issues in caseNumberWriter
or one of its transient dependencies start implementingIDisposable
(which could result in a memory leak) or in caseNumberWriter
has direct or indirect dependencies with theScoped
lifestyle (which would make those dependenciesSingletons
). - Registering
DispatchingNumberWriter
asTransient
will have the desired effect except in case it gets (accidentally) directly or indirectly injected intoSingleton
consumer. Because in that case you'll get the same behavior as described in the previous point withDispatchingNumberWriter
registered asSingleton
. Although the problem isn't different when injecting aScoped
DispatchingNumberWriter
into aSingleton
consumer, MS.DI prevents the injection ofScoped
dependencies intoSingleton
consumers, because it is known pitfall to prevent.
- Registering
What is dependency injection?
Dependency Injection is passing dependency to other objects or framework( dependency injector).
Dependency injection makes testing easier. The injection can be done through constructor.
SomeClass()
has its constructor as following:
public SomeClass() {
myObject = Factory.getObject();
}
Problem:
If myObject
involves complex tasks such as disk access or network access, it is hard to do unit test on SomeClass()
. Programmers have to mock myObject
and might intercept the factory call.
Alternative solution:
- Passing
myObject
in as an argument to the constructor
public SomeClass (MyClass myObject) {
this.myObject = myObject;
}
myObject
can be passed directly which makes testing easier.
- One common alternative is defining a do-nothing constructor. Dependency injection can be done through setters. (h/t @MikeVella).
- Martin Fowler documents a third alternative (h/t @MarcDix), where classes explicitly implement an interface for the dependencies programmers wish injected.
It is harder to isolate components in unit testing without dependency injection.
In 2013, when I wrote this answer, this was a major theme on the Google Testing Blog. It remains the biggest advantage to me, as programmers not always need the extra flexibility in their run-time design (for instance, for service locator or similar patterns). Programmers often need to isolate the classes during testing.
Related Topics
Mstest Cannot Find the Assembly
How to Hide Wpf Datagrid Columns Depending on a Property
Moving Mouse Cursor Programmatically
Sortedlist<>, Sorteddictionary<> and Dictionary<>
Main: Not All Code Paths Return a Value
Add Custom Header in Httpwebrequest
Convert String to Int Array Using Linq
Datetime to String with Time Zone
JSONconvert.Serializeobject Always Return {} in Xamarinforms
How to Copy the Contents of a String to the Clipboard in C#
What's a Good Way of Doing String Templating in .Net
What's the Point of a Lambda Expression
Why Are Some Members Missing When Trying to Print an Object by Serializing to JSON
Create a .Txt File If Doesn't Exist, and If It Does Append a New Line