Sometimes you need to build up an existing composition root and inject all of its dependencies, in which case the Builder method will be useful, as in the example below:
using Shouldly;
using Pure.DI;
DI.Setup(nameof(Composition))
.Bind().To(Guid.NewGuid)
.Bind().To<PhotonBlaster>()
.Builder<Player>("Equip");
var composition = new Composition();
// The Game Engine instantiates the Player entity,
// so we need to inject dependencies into the existing instance.
var player = composition.Equip(new Player());
player.Id.ShouldNotBe(Guid.Empty);
player.Weapon.ShouldBeOfType<PhotonBlaster>();
interface IWeapon;
class PhotonBlaster : IWeapon;
interface IGameEntity
{
Guid Id { get; }
IWeapon? Weapon { get; }
}
record Player : IGameEntity
{
public Guid Id { get; private set; } = Guid.Empty;
// The Dependency attribute specifies to perform an injection
[Dependency]
public IWeapon? Weapon { get; set; }
[Dependency]
public void SetId(Guid id) => Id = id;
}Running this code sample locally
- Make sure you have the .NET SDK 10.0 or later installed
dotnet --list-sdk- Create a net10.0 (or later) console application
dotnet new console -n Sampledotnet add package Pure.DI
dotnet add package Shouldly- Copy the example code into the Program.cs file
You are ready to run the example 🚀
dotnet runImportant Notes:
- The default builder method name is
BuildUp - The first argument to the builder method is always the instance to be built
Advantages:
- Allows working with pre-existing objects
- Provides flexibility in dependency injection
- Supports partial injection of dependencies
- Can be used with legacy code
Use Cases:
- When objects are created outside the DI
- For working with third-party libraries
- When migrating existing code to DI
- For complex object graphs where full construction is not feasible
The following partial class will be generated:
partial class Composition
{
#if NET9_0_OR_GREATER
private readonly Lock _lock = new Lock();
#else
private readonly Object _lock = new Object();
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Player Equip(Player buildingInstance)
{
if (buildingInstance is null) throw new ArgumentNullException(nameof(buildingInstance));
Player transientPlayer241;
Player localBuildingInstance = buildingInstance;
Guid transientGuid244 = Guid.NewGuid();
localBuildingInstance.Weapon = new PhotonBlaster();
localBuildingInstance.SetId(transientGuid244);
transientPlayer241 = localBuildingInstance;
return transientPlayer241;
}
}Class diagram:
---
config:
maxTextSize: 2147483647
maxEdges: 2147483647
class:
hideEmptyMembersBox: true
---
classDiagram
Guid --|> IComparable
Guid --|> IComparableᐸGuidᐳ
Guid --|> IEquatableᐸGuidᐳ
Guid --|> IFormattable
Guid --|> IParsableᐸGuidᐳ
Guid --|> ISpanFormattable
Guid --|> ISpanParsableᐸGuidᐳ
Guid --|> IUtf8SpanFormattable
Guid --|> IUtf8SpanParsableᐸGuidᐳ
PhotonBlaster --|> IWeapon
Composition ..> Player : Player Equip(Pure.DI.UsageTests.Basics.BuilderScenario.Player buildingInstance)
Player *-- Guid : Guid
Player *-- PhotonBlaster : IWeapon
namespace Pure.DI.UsageTests.Basics.BuilderScenario {
class Composition {
<<partial>>
+Player Equip(Pure.DI.UsageTests.Basics.BuilderScenario.Player buildingInstance)
}
class IWeapon {
<<interface>>
}
class PhotonBlaster {
<<class>>
+PhotonBlaster()
}
class Player {
<<record>>
+IWeapon Weapon
+SetId(Guid id) : Void
}
}
namespace System {
class Guid {
<<struct>>
}
class IComparable {
<<interface>>
}
class IComparableᐸGuidᐳ {
<<interface>>
}
class IEquatableᐸGuidᐳ {
<<interface>>
}
class IFormattable {
<<interface>>
}
class IParsableᐸGuidᐳ {
<<interface>>
}
class ISpanFormattable {
<<interface>>
}
class ISpanParsableᐸGuidᐳ {
<<interface>>
}
class IUtf8SpanFormattable {
<<interface>>
}
class IUtf8SpanParsableᐸGuidᐳ {
<<interface>>
}
}