Shows how to declare a binding directly on an implementation type with a custom attribute. A custom attribute can combine contract type, lifetime, and tag metadata by registering argument positions in the composition setup.
using Shouldly;
using Pure.DI;
DI.Setup(nameof(Composition))
.TypeAttribute<ServiceAttribute<TT>>()
.LifetimeAttribute<ServiceAttribute<TT>>()
.TagAttribute<ServiceAttribute<TT>>(1)
// Composition root
.Root<IMessageWriter>("Writer", "console");
var composition = new Composition();
var writer = composition.Writer;
writer.Write("Pure.DI");
writer.ShouldBeOfType<ConsoleMessageWriter>();
writer.ShouldBeSameAs(composition.Writer);
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
class ServiceAttribute<T> : Attribute
{
public ServiceAttribute(
Lifetime lifetime = Lifetime.Transient,
object? tag = null)
{
}
}
interface IMessageWriter
{
void Write(string message);
}
[Service<IMessageWriter>(Lifetime.Singleton, "console")]
class ConsoleMessageWriter : IMessageWriter
{
public void Write(string message) => Console.WriteLine(message);
}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
Implementation-level binding attributes are useful when the implementation assembly should describe its DI role while keeping the composition concise. Custom attributes participate in the same merge rules as the built-in Bind, Type, Tag, and Lifetime attributes: attributes in one square-bracket group form one binding, while separate Bind groups create separate bindings.
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
private ConsoleMessageWriter? _singletonConsoleMessageWriter1;
public IMessageWriter Writer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
if (_singletonConsoleMessageWriter1 is null)
lock (_lock)
if (_singletonConsoleMessageWriter1 is null)
{
_singletonConsoleMessageWriter1 = new ConsoleMessageWriter();
}
return _singletonConsoleMessageWriter1;
}
}
}Class diagram:
---
config:
class:
hideEmptyMembersBox: true
---
classDiagram
ConsoleMessageWriter --|> IMessageWriter : "console"
Composition ..> ConsoleMessageWriter : IMessageWriter Writer
namespace Pure.DI.UsageTests.Attributes.CustomBindAttributeScenario {
class Composition {
<<partial>>
+IMessageWriter Writer
}
class ConsoleMessageWriter {
<<class>>
+ConsoleMessageWriter()
}
class IMessageWriter {
<<interface>>
}
}
See also: