Skip to content

Latest commit

 

History

History
170 lines (147 loc) · 3.91 KB

File metadata and controls

170 lines (147 loc) · 3.91 KB

Injections on demand with arguments

This example uses a parameterized factory so dependencies can be created with runtime arguments. The service creates sensors with specific IDs at instantiation time. It is a type-safe way to combine DI-managed creation with runtime data.

using Shouldly;
using Pure.DI;
using System.Collections.Generic;

DI.Setup(nameof(Composition))
    .Bind().To<Sensor>()
    .Bind().To<SmartHome>()

    // Composition root
    .Root<ISmartHome>("SmartHome");

var composition = new Composition();
var smartHome = composition.SmartHome;
var sensors = smartHome.Sensors;

sensors.Count.ShouldBe(2);
sensors[0].Id.ShouldBe(101);
sensors[1].Id.ShouldBe(102);

interface ISensor
{
    int Id { get; }
}

class Sensor(int id) : ISensor
{
    public int Id { get; } = id;
}

interface ISmartHome
{
    IReadOnlyList<ISensor> Sensors { get; }
}

class SmartHome(Func<int, ISensor> sensorFactory) : ISmartHome
{
    public IReadOnlyList<ISensor> Sensors { get; } =
    [
        // Use the injected factory to create a sensor with ID 101
        sensorFactory(101),

        // Create another sensor with ID 102
        sensorFactory(102)
    ];
}
Running this code sample locally
dotnet --list-sdk
  • Create a net10.0 (or later) console application
dotnet new console -n Sample
dotnet 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 run

Delayed dependency instantiation:

  • Injection of dependencies requiring runtime parameters
  • Creation of distinct instances with different configurations
  • Type-safe resolution of dependencies with constructor arguments Limitations: runtime arguments improve flexibility but can increase coupling between call sites and construction signatures. Common pitfalls:
  • Passing infrastructure concerns as runtime arguments instead of normal dependencies.
  • Duplicating argument validation logic across consumers. See also: Injection on demand, Root arguments.

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

  public ISmartHome SmartHome
  {
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    get
    {
      Func<int, ISensor> perBlockFunc299;
      Func<int, ISensor> localFactory1 = new Func<int, ISensor>((int localArg1) =>
      {
        lock (_lock)
        {
          int overriddenInt32 = localArg1;
          return new Sensor(overriddenInt32);
        }
      });
      perBlockFunc299 = localFactory1;
      return new SmartHome(perBlockFunc299);
    }
  }
}

Class diagram:

---
 config:
  maxTextSize: 2147483647
  maxEdges: 2147483647
  class:
   hideEmptyMembersBox: true
---
classDiagram
	Sensor --|> ISensor
	SmartHome --|> ISmartHome
	Composition ..> SmartHome : ISmartHome SmartHome
	Sensor *--  Int32 : Int32
	SmartHome o-- "PerBlock" FuncᐸInt32ˏISensorᐳ : FuncᐸInt32ˏISensorᐳ
	FuncᐸInt32ˏISensorᐳ *--  Sensor : ISensor
	namespace Pure.DI.UsageTests.Basics.InjectionOnDemandWithArgumentsScenario {
		class Composition {
		<<partial>>
		+ISmartHome SmartHome
		}
		class ISensor {
			<<interface>>
		}
		class ISmartHome {
			<<interface>>
		}
		class Sensor {
				<<class>>
			+Sensor(Int32 id)
		}
		class SmartHome {
				<<class>>
			+SmartHome(FuncᐸInt32ˏISensorᐳ sensorFactory)
		}
	}
	namespace System {
		class FuncᐸInt32ˏISensorᐳ {
				<<delegate>>
		}
		class Int32 {
			<<struct>>
		}
	}
Loading