Dependency Injection - New Instance Required in Several of a Classes Methods

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 new NumberWriter. This allows the NumberWriter 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 as Transient; otherwise instances might still be reused.
  • The DispatchingNumberWriter is registered as Scoped, which the safest lifestyle for this class, because:
    • Registering DispatchingNumberWriter as Singleton will cause it's c parameter and the call to its GetRequiredService method to run in the container's global scope. This can cause issues in case NumberWriter or one of its transient dependencies start implementing IDisposable (which could result in a memory leak) or in case NumberWriter has direct or indirect dependencies with the Scoped lifestyle (which would make those dependencies Singletons).
    • Registering DispatchingNumberWriter as Transient will have the desired effect except in case it gets (accidentally) directly or indirectly injected into Singleton consumer. Because in that case you'll get the same behavior as described in the previous point with DispatchingNumberWriter registered as Singleton. Although the problem isn't different when injecting a Scoped DispatchingNumberWriter into a Singleton consumer, MS.DI prevents the injection of Scoped dependencies into Singleton consumers, because it is known pitfall to prevent.

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



Leave a reply



Submit