Skip to content

Latest commit

 

History

History
136 lines (113 loc) · 3.19 KB

member-ordinal-attribute.md

File metadata and controls

136 lines (113 loc) · 3.19 KB

Member ordinal attribute

CSharp

When applied to a property or field, these type members will also participate in dependency injection in the appropriate order from smallest value to largest.

interface IPerson
{
    string Name { get; }
}

class Person : IPerson
{
    private readonly StringBuilder _name = new();

    public string Name => _name.ToString();

    // The Ordinal attribute specifies to perform an injection,
    // the integer value in the argument specifies
    // the ordinal of injection
    [Ordinal(0)]
    public int Id;

    [Ordinal(1)]
    public string FirstName
    {
        set
        {
            _name.Append(Id);
            _name.Append(' ');
            _name.Append(value);
        }
    }

    [Ordinal(2)]
    public DateTime Birthday
    {
        set
        {
            _name.Append(' ');
            _name.Append($"{value:yyyy-MM-dd}");
        }
    }
}

DI.Setup(nameof(PersonComposition))
    .Arg<int>("personId")
    .Arg<string>("personName")
    .Arg<DateTime>("personBirthday")
    .Bind().To<Person>()

    // Composition root
    .Root<IPerson>("Person");

var composition = new PersonComposition(
    personId: 123,
    personName: "Nik",
    personBirthday: new DateTime(1977, 11, 16));

var person = composition.Person;
person.Name.ShouldBe("123 Nik 1977-11-16");

The attribute Ordinal is part of the API, but you can use your own attribute at any time, and this allows you to define them in the assembly and namespace you want.

The following partial class will be generated:

partial class PersonComposition
{
  private readonly PersonComposition _root;

  private readonly int _argPersonId;
  private readonly string _argPersonName;
  private readonly DateTime _argPersonBirthday;

  public PersonComposition(int personId, string personName, DateTime personBirthday)
  {
    _argPersonId = personId;
    _argPersonName = personName ?? throw new ArgumentNullException(nameof(personName));
    _argPersonBirthday = personBirthday;
    _root = this;
  }

  internal PersonComposition(PersonComposition parentScope)
  {
    _root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root;
    _argPersonId = _root._argPersonId;
    _argPersonName = _root._argPersonName;
    _argPersonBirthday = _root._argPersonBirthday;
  }

  public IPerson Person
  {
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    get
    {
      Person transientPerson0 = new Person();
      transientPerson0.Id = _argPersonId;
      transientPerson0.FirstName = _argPersonName;
      transientPerson0.Birthday = _argPersonBirthday;
      return transientPerson0;
    }
  }
}

Class diagram:

classDiagram
	class PersonComposition {
		<<partial>>
		+IPerson Person
	}
	class Int32
	class String
	class DateTime
	Person --|> IPerson
	class Person {
		+Person()
		+Int32 Id
		+String FirstName
		+DateTime Birthday
	}
	class IPerson {
		<<interface>>
	}
	PersonComposition ..> Person : IPerson Person
	Person o-- Int32 : Argument "personId"
	Person o-- String : Argument "personName"
	Person o-- DateTime : Argument "personBirthday"