To use custom attributes, derive from System.Attribute and register them with the setup API:
TagAttributeOrdinalAttributeTypeAttributeYou can also use combined attributes. Each registration method can take an optional argument index (default is 0) that specifies where to read tag, ordinal, or type metadata.
using Shouldly;
using Pure.DI;
DI.Setup(nameof(PersonComposition))
.TagAttribute<MyTagAttribute>()
.OrdinalAttribute<MyOrdinalAttribute>()
.TypeAttribute<MyTypeAttribute>()
.TypeAttribute<MyGenericTypeAttribute<TT>>()
.Arg<int>("personId")
.Bind().To(() => new Uri("https://github.com/DevTeam/Pure.DI"))
.Bind("NikName").To(() => "Nik")
.Bind().To<Person>()
// Composition root
.Root<IPerson>("Person");
var composition = new PersonComposition(personId: 123);
var person = composition.Person;
person.ToString().ShouldBe("123 Nik https://github.com/DevTeam/Pure.DI");
[AttributeUsage(
AttributeTargets.Constructor
| AttributeTargets.Method |
AttributeTargets.Property |
AttributeTargets.Field)]
class MyOrdinalAttribute(int ordinal) : Attribute;
[AttributeUsage(
AttributeTargets.Parameter
| AttributeTargets.Property
| AttributeTargets.Field)]
class MyTagAttribute(object tag) : Attribute;
[AttributeUsage(
AttributeTargets.Parameter
| AttributeTargets.Property
| AttributeTargets.Field)]
class MyTypeAttribute(Type type) : Attribute;
[AttributeUsage(
AttributeTargets.Parameter
| AttributeTargets.Property
| AttributeTargets.Field)]
class MyGenericTypeAttribute<T> : Attribute;
interface IPerson;
class Person([MyTag("NikName")] string name) : IPerson
{
private object? _state;
[MyOrdinal(1)] [MyType(typeof(int))] internal object Id = "";
[MyOrdinal(2)]
public void Initialize([MyGenericType<Uri>] object state) =>
_state = state;
public override string ToString() => $"{Id} {name} {_state}";
}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 runNote
Custom attributes provide extensibility for advanced scenarios where standard attributes don't meet specific requirements.
The following partial class will be generated:
partial class PersonComposition
{
#if NET9_0_OR_GREATER
private readonly Lock _lock;
#else
private readonly Object _lock;
#endif
private readonly int _argPersonId;
[OrdinalAttribute(128)]
public PersonComposition(int personId)
{
_argPersonId = personId;
#if NET9_0_OR_GREATER
_lock = new Lock();
#else
_lock = new Object();
#endif
}
public IPerson Person
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
string transientString194 = "Nik";
Uri transientUri196 = new Uri("https://github.com/DevTeam/Pure.DI");
var transientPerson193 = new Person(transientString194);
transientPerson193.Id = _argPersonId;
transientPerson193.Initialize(transientUri196);
return transientPerson193;
}
}
}Class diagram:
---
config:
maxTextSize: 2147483647
maxEdges: 2147483647
class:
hideEmptyMembersBox: true
---
classDiagram
Uri --|> IEquatableᐸUriᐳ
Uri --|> IFormattable
Uri --|> ISpanFormattable
Uri --|> ISerializable
Person --|> IPerson
PersonComposition ..> Person : IPerson Person
Person o-- Int32 : Argument "personId"
Person *-- Uri : Uri
Person *-- String : "NikName" String
namespace Pure.DI.UsageTests.Attributes.CustomAttributesScenario {
class IPerson {
<<interface>>
}
class Person {
<<class>>
+Person(String name)
~Object Id
+Initialize(Object state) : Void
}
class PersonComposition {
<<partial>>
+IPerson Person
}
}
namespace System {
class IEquatableᐸUriᐳ {
<<interface>>
}
class IFormattable {
<<interface>>
}
class Int32 {
<<struct>>
}
class ISpanFormattable {
<<interface>>
}
class String {
<<class>>
}
class Uri {
<<class>>
}
}
namespace System.Runtime.Serialization {
class ISerializable {
<<interface>>
}
}