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<WiFi>()
// Creates a builder based on the name template
// for each type inherited from IDevice.
// These types must be available at this point in the code.
.Builders<IDevice>("Install{type}");
var composition = new Composition();
var webcam = composition.InstallWebcam(new Webcam());
webcam.Id.ShouldNotBe(Guid.Empty);
webcam.Network.ShouldBeOfType<WiFi>();
var thermostat = composition.InstallThermostat(new Thermostat());
thermostat.Id.ShouldBe(Guid.Empty);
thermostat.Network.ShouldBeOfType<WiFi>();
// Uses a common method to build an instance
IDevice device = new Webcam();
device = composition.InstallIDevice(device);
device.ShouldBeOfType<Webcam>();
device.Id.ShouldNotBe(Guid.Empty);
device.Network.ShouldBeOfType<WiFi>();
interface INetwork;
class WiFi : INetwork;
interface IDevice
{
Guid Id { get; }
INetwork? Network { get; }
}
record Webcam : IDevice
{
public Guid Id { get; private set; } = Guid.Empty;
// The Dependency attribute specifies to perform an injection
[Dependency]
public INetwork? Network { get; set; }
[Dependency]
public void SetId(Guid id) => Id = id;
}
record Thermostat : IDevice
{
public Guid Id => Guid.Empty;
// The Dependency attribute specifies to perform an injection
[Dependency]
public INetwork? Network { get; set; }
}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 runThe default builder method name is BuildUp. The first argument to this method will always be the instance to be built.
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 Webcam InstallWebcam(Webcam buildingInstance)
{
if (buildingInstance is null) throw new ArgumentNullException(nameof(buildingInstance));
Webcam transientWebcam259;
Webcam localBuildingInstance6 = buildingInstance;
Guid transientGuid262 = Guid.NewGuid();
localBuildingInstance6.Network = new WiFi();
localBuildingInstance6.SetId(transientGuid262);
transientWebcam259 = localBuildingInstance6;
return transientWebcam259;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Thermostat InstallThermostat(Thermostat buildingInstance)
{
if (buildingInstance is null) throw new ArgumentNullException(nameof(buildingInstance));
Thermostat transientThermostat256;
Thermostat localBuildingInstance5 = buildingInstance;
localBuildingInstance5.Network = new WiFi();
transientThermostat256 = localBuildingInstance5;
return transientThermostat256;
}
#pragma warning disable CS0162
[MethodImpl(MethodImplOptions.NoInlining)]
public IDevice InstallIDevice(IDevice buildingInstance)
{
if (buildingInstance is null) throw new ArgumentNullException(nameof(buildingInstance));
switch (buildingInstance)
{
case Webcam Webcam:
return InstallWebcam(Webcam);
case Thermostat Thermostat:
return InstallThermostat(Thermostat);
default:
throw new ArgumentException($"Unable to build an instance of typeof type {buildingInstance.GetType()}.", "buildingInstance");
}
return buildingInstance;
}
#pragma warning restore CS0162
}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ᐳ
WiFi --|> INetwork
Composition ..> IDevice : IDevice InstallIDevice(Pure.DI.UsageTests.Basics.BuildersWithNameTemplateScenario.IDevice buildingInstance)
Composition ..> Thermostat : Thermostat InstallThermostat(Pure.DI.UsageTests.Basics.BuildersWithNameTemplateScenario.Thermostat buildingInstance)
Composition ..> Webcam : Webcam InstallWebcam(Pure.DI.UsageTests.Basics.BuildersWithNameTemplateScenario.Webcam buildingInstance)
Webcam *-- Guid : Guid
Webcam *-- WiFi : INetwork
Thermostat *-- WiFi : INetwork
namespace Pure.DI.UsageTests.Basics.BuildersWithNameTemplateScenario {
class Composition {
<<partial>>
+IDevice InstallIDevice(Pure.DI.UsageTests.Basics.BuildersWithNameTemplateScenario.IDevice buildingInstance)
+Thermostat InstallThermostat(Pure.DI.UsageTests.Basics.BuildersWithNameTemplateScenario.Thermostat buildingInstance)
+Webcam InstallWebcam(Pure.DI.UsageTests.Basics.BuildersWithNameTemplateScenario.Webcam buildingInstance)
}
class IDevice {
<<interface>>
}
class INetwork {
<<interface>>
}
class Thermostat {
<<record>>
+INetwork Network
}
class Webcam {
<<record>>
+INetwork Network
+SetId(Guid id) : Void
}
class WiFi {
<<class>>
+WiFi()
}
}
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>>
}
}