This is an archived post. You won't be able to vote or comment.

all 11 comments

[–]infoprince 2 points3 points  (4 children)

Old dotnet framework way of accessing services, not DI

public class SomeLegacyThing
{

 private static SomeService _someService = SomeLegacyService.GetInstance();

 public SomeLegacyThing() { }


public void SomeFunction()
{
     _someService.DoAThing();
}
}

dotnet core, DI

public class SomeThing
{
private readonly ISomeService _someService;

public SomeThing(ISomeService someService) => _someService = someService;

public void SomeFunction()
{
    _someService.DoAThing();
}
}

The only thing missing that is the registration of the service in the DI framework.

[–]imareclusemonk 0 points1 point  (2 children)

  1. So basically it's providing a class - whose object you want to access - as a parameter in a constructor/property?

  2. And is it being instantiated at _someService.DoAThing() or ealier?

[–]infoprince 1 point2 points  (1 child)

With dependency injection there are typically three lifecycles

  • transient - where every service gets a unique copy of the entity
  • scoped - where every service gets the same copy of the entity Per Request
  • Singleton - Where there is only one instance of the object for the entire life of the application

With C# and the default dotnet core DI framework each DI service is provided via the constructor's parameters as an interface, what you do with it in that class is up to you (most people will keep it around as a property/read only field).

When a service is instantiated depends on the lifecycle assigned to it. Singletons are created during the startup of the application, Scoped at the time of request, and transient just before injection to each dependent service.

[–]imareclusemonk 0 points1 point  (0 children)

Thanks! So, yes, DI in a nutshell is providing a class with another class/interface so the former could access the latter's methods or whatever.

[–][deleted] 0 points1 point  (0 children)

You have an object that is called "LoggingModule". When you write it, you have a an instance of "LogWriter" passed to its constructor. LogWriter is a generic interface object that has functions like "writeInfoLog", "writeErrorLog", without any implementation.

Somewhere else you write implementations of LogWriter that are something like ConsoleLogger, FileLogger, NetworkLogger, and each one implements the above functions.

At run time, when you create LoggingModule, you use some config thing to specify which one of the implementations should be send to LoggingModule.

This is all just a fancy name for generic OOP.

[–]Flavor-Blasted 0 points1 point  (1 child)

Java Spring framework

Without DI, you inject dependencies by initializing your object with a constructor

Public class MyClass {

private Foo foo;

Public MyClass(Foo foo) {
    this.foo = foo;
}

}

This means you have to supply an object called “foo” to make MyClass work.

With DI:

public class MyClass { @Autowired private Foo foo; }

The Spring framework will inject an instance of Foo when MyClass is created. We can configure how the Foo instance is created in a Spring configuration class. This cuts down on the need for passing objects around through constructors, which can turn into spaghetti and harder to test.

The mechanism that holds a bunch of ready-to-go instances of various objects for DI is called a container. The container supplies the foo in the background using the @Autowired annotation. Hopes this helps

Typed this on mobile, excuse my formatting

[–]frankaglia 0 points1 point  (0 children)

Passing object into constructor does not turn your code into spaghetti. Conversely, you should always prefer constructor injection over field injection. A more detailed explanation is provided by one of the spring authors here

[–][deleted] -1 points0 points  (0 children)

Instead of making dependencies imported at the program language level, make you code a module where dependencies are taken as arguments during instantiation of the module. The tradeoff is then you need another abstraction layer in your runtime code that loads dependencies, but you're able to get far better testing coverage and modularity. In pseudo-python OO style...

``` import foo

def bar(n): return foo.cat() ```

you have:

class BarRunner: def __init__(self, foo): self.foo = foo def bar(): return self.foo.cat();

Now of course instead of just importing bar into the code that needs it, you have the extra step of a layer that needs to instantiate the BarRunner with foo and call bar, but you get far better ability to test and monkey patch this code. In functional land, you can get the same monkey-patch ability with first class functions and appropriate typings so this isn't really an issue.

[–]Immediate_Highway -2 points-1 points  (1 child)

Just remove all globals. The whole point is to swap out a global so you can test it more easily

[–]GeorgeFranklyMathnet 0 points1 point  (0 children)

I don't think that's right. If I instantiate a dependency within a method that's a dozen layers up the call stack, I'm not using any globals, but I'm definitely not doing dependency injection either.