Skip to content

Latest commit

 

History

History
180 lines (147 loc) · 4.81 KB

class-arguments.md

File metadata and controls

180 lines (147 loc) · 4.81 KB

Class arguments

CSharp

Sometimes you need to pass some state to a composition class to use it when resolving dependencies. To do this, just use the Arg<T>(string argName) method, specify the type of argument and its name. You can also specify a tag for each argument. You can then use them as dependencies when building the object graph. If you have multiple arguments of the same type, just use tags to distinguish them. The values of the arguments are manipulated when you create a composition class by calling its constructor. It is important to remember that only those arguments that are used in the object graph will appear in the constructor. Arguments that are not involved will not be added to the constructor arguments.

Note

Actually, class arguments work like normal bindings. The difference is that they bind to the values of the arguments. These values will be injected wherever they are required.

using Shouldly;
using Pure.DI;

DI.Setup(nameof(Composition))
    .Bind<IDependency>().To<Dependency>()
    .Bind<IService>().To<Service>()

    // Composition root "MyRoot"
    .Root<IService>("MyService")

    // Some kind of identifier
    .Arg<int>("id")

    // An argument can be tagged (e.g., tag "my service name")
    // to be injectable by type and this tag
    .Arg<string>("serviceName", "my service name")
    .Arg<string>("dependencyName");

var composition = new Composition(id: 123, serviceName: "Abc", dependencyName: "Xyz");

// service = new Service("Abc", new Dependency(123, "Xyz"));
var service = composition.MyService;

service.Name.ShouldBe("Abc");
service.Dependency.Id.ShouldBe(123);
service.Dependency.Name.ShouldBe("Xyz");

interface IDependency
{
    int Id { get; }

    string Name { get; }
}

class Dependency(int id, string name) : IDependency
{
    public int Id { get; } = id;

    public string Name { get; } = name;
}

interface IService
{
    string Name { get; }

    IDependency Dependency { get; }
}

class Service(
    // The tag allows to specify the injection point accurately.
    // This is useful, for example, when the type is the same.
    [Tag("my service name")] string name,
    IDependency dependency) : IService
{
    public string Name { get; } = name;

    public IDependency Dependency { get; } = dependency;
}
Running this code sample locally
dotnet --list-sdk
  • Create a net9.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

The following partial class will be generated:

partial class Composition
{
  private readonly Composition _root;

  private readonly int _argId;
  private readonly string _argServiceName;
  private readonly string _argDependencyName;

  [OrdinalAttribute(128)]
  public Composition(int id, string serviceName, string dependencyName)
  {
    _argId = id;
    _argServiceName = serviceName ?? throw new ArgumentNullException(nameof(serviceName));
    _argDependencyName = dependencyName ?? throw new ArgumentNullException(nameof(dependencyName));
    _root = this;
  }

  internal Composition(Composition parentScope)
  {
    _root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root;
    _argId = _root._argId;
    _argServiceName = _root._argServiceName;
    _argDependencyName = _root._argDependencyName;
  }

  public IService MyService
  {
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    get
    {
      return new Service(_argServiceName, new Dependency(_argId, _argDependencyName));
    }
  }
}

Class diagram:

---
 config:
  class:
   hideEmptyMembersBox: true
---
classDiagram
	Service --|> IService
	Dependency --|> IDependency
	Composition ..> Service : IService MyService
	Service o-- String : "my service name"  Argument "serviceName"
	Service *--  Dependency : IDependency
	Dependency o-- Int32 : Argument "id"
	Dependency o-- String : Argument "dependencyName"
	namespace Pure.DI.UsageTests.Basics.ClassArgumentsScenario {
		class Composition {
		<<partial>>
		+IService MyService
		}
		class Dependency {
			+Dependency(Int32 id, String name)
		}
		class IDependency {
			<<interface>>
		}
		class IService {
			<<interface>>
		}
		class Service {
			+Service(String name, IDependency dependency)
		}
	}
	namespace System {
		class Int32 {
				<<struct>>
		}
		class String {
		}
	}
Loading