This example demonstrates the recommended approach of using abstractions instead of implementations when injecting dependencies.
using Pure.DI;
DI.Setup(nameof(Composition))
// Binding abstractions to their implementations
.Bind<IDependency>().To<Dependency>()
.Bind<IService>().To<Service>()
// Specifies to create a composition root
// of type "Program" with the name "Root"
.Root<Program>("Root");
var composition = new Composition();
// var root = new Program(new Service(new Dependency()));
var root = composition.Root;
root.Run();
interface IDependency;
class Dependency : IDependency;
interface IService
{
void DoSomething();
}
class Service(IDependency dependency) : IService
{
public void DoSomething()
{
}
}
partial class Program(IService service)
{
public void Run() => service.DoSomething();
}
Running this code sample locally
- Make sure you have the .NET SDK 9.0 or later is installed
dotnet --list-sdk
- Create a net9.0 (or later) console application
dotnet new console -n Sample
- Add reference to NuGet package
dotnet add package Pure.DI
- Copy the example code into the Program.cs file
You are ready to run the example 🚀
dotnet run
Usually the biggest block in the setup is the chain of bindings, which describes which implementation corresponds to which abstraction. This is necessary so that the code generator can build a composition of objects using only NOT abstract types. This is true because the cornerstone of DI technology implementation is the principle of abstraction-based programming rather than concrete class-based programming. Thanks to it, it is possible to replace one concrete implementation by another. And each implementation can correspond to an arbitrary number of abstractions.
Tip
Even if the binding is not defined, there is no problem with the injection, but obviously under the condition that the consumer requests an injection NOT of abstract type.
The following partial class will be generated:
partial class Composition
{
private readonly Composition _root;
[OrdinalAttribute(256)]
public Composition()
{
_root = this;
}
internal Composition(Composition parentScope)
{
_root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root;
}
public Program Root
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return new Program(new Service(new Dependency()));
}
}
}
Class diagram:
---
config:
class:
hideEmptyMembersBox: true
---
classDiagram
Service --|> IService
Dependency --|> IDependency
Composition ..> Program : Program Root
Program *-- Service : IService
Service *-- Dependency : IDependency
namespace Pure.DI.UsageTests.Basics.InjectionsOfAbstractionsScenario {
class Composition {
<<partial>>
+Program Root
}
class Dependency {
+Dependency()
}
class IDependency {
<<interface>>
}
class IService {
<<interface>>
}
class Program {
}
class Service {
+Service(IDependency dependency)
}
}