Tag.Unique is useful to register a binding with a unique tag. It will not be available through the composition root or Resolve methods directly, but can be injected in compositions as some kind of enumeration.
Use this to aggregate multiple implementations without exposing each one as a direct root.
using Shouldly;
using Pure.DI;
using System.Collections.Immutable;
DI.Setup(nameof(Composition))
.Bind<INotificationChannel<TT>>(Tag.Unique).To<EmailChannel<TT>>()
.Bind<INotificationChannel<TT>>(Tag.Unique).To<SmsChannel<TT>>()
.Bind<INotificationService<TT>>().To<NotificationService<TT>>()
// Composition root
.Root<INotificationService<string>>("NotificationService");
var composition = new Composition();
var notificationService = composition.NotificationService;
notificationService.Channels.Length.ShouldBe(2);
interface INotificationChannel<T>;
class EmailChannel<T> : INotificationChannel<T>;
class SmsChannel<T> : INotificationChannel<T>;
interface INotificationService<T>
{
ImmutableArray<INotificationChannel<T>> Channels { get; }
}
class NotificationService<T>(IEnumerable<INotificationChannel<T>> channels)
: INotificationService<T>
{
public ImmutableArray<INotificationChannel<T>> Channels { get; }
= [..channels];
}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 runLimitations: unique-tag bindings are intentionally hidden from direct resolve; document this to avoid confusion in integration code. See also: Tags, Enumerable.
The following partial class will be generated:
partial class Composition
{
public INotificationService<string> NotificationService
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
IEnumerable<INotificationChannel<string>> EnumerationOf_perBlockIEnumerable137()
{
yield return new EmailChannel<string>();
yield return new SmsChannel<string>();
}
return new NotificationService<string>(EnumerationOf_perBlockIEnumerable137());
}
}
}Class diagram:
---
config:
maxTextSize: 2147483647
maxEdges: 2147483647
class:
hideEmptyMembersBox: true
---
classDiagram
NotificationServiceᐸStringᐳ --|> INotificationServiceᐸStringᐳ
EmailChannelᐸStringᐳ --|> INotificationChannelᐸStringᐳ : "Unique tag #45"
SmsChannelᐸStringᐳ --|> INotificationChannelᐸStringᐳ : "Unique tag #46"
Composition ..> NotificationServiceᐸStringᐳ : INotificationServiceᐸStringᐳ NotificationService
NotificationServiceᐸStringᐳ o-- "PerBlock" IEnumerableᐸINotificationChannelᐸStringᐳᐳ : IEnumerableᐸINotificationChannelᐸStringᐳᐳ
IEnumerableᐸINotificationChannelᐸStringᐳᐳ *-- EmailChannelᐸStringᐳ : "Unique tag #45" INotificationChannelᐸStringᐳ
IEnumerableᐸINotificationChannelᐸStringᐳᐳ *-- SmsChannelᐸStringᐳ : "Unique tag #46" INotificationChannelᐸStringᐳ
namespace Pure.DI.UsageTests.Advanced.TagUniqueScenario {
class Composition {
<<partial>>
+INotificationServiceᐸStringᐳ NotificationService
}
class EmailChannelᐸStringᐳ {
<<class>>
+EmailChannel()
}
class INotificationChannelᐸStringᐳ {
<<interface>>
}
class INotificationServiceᐸStringᐳ {
<<interface>>
}
class NotificationServiceᐸStringᐳ {
<<class>>
+NotificationService(IEnumerableᐸINotificationChannelᐸStringᐳᐳ channels)
}
class SmsChannelᐸStringᐳ {
<<class>>
+SmsChannel()
}
}
namespace System.Collections.Generic {
class IEnumerableᐸINotificationChannelᐸStringᐳᐳ {
<<interface>>
}
}