@@ -3358,6 +3358,72 @@ In addition to arrays, other collection types are also supported, such as:
33583358- System.Collections.Immutable.IImmutableStack<T >
33593359And of course this list can easily be supplemented on its own.
33603360
3361+ ## Dictionary
3362+
3363+ Demonstrates dictionary injection using IReadOnlyDictionary<TKey, TValue>, allowing key-value pair collection injection.
3364+
3365+ ``` c#
3366+ using Shouldly ;
3367+ using Pure .DI ;
3368+
3369+ DI .Setup (nameof (Composition ))
3370+ .Bind (Tag .Unique ).To ((EmailChannel chanel ) => new KeyValuePair <Channel , INotificationChannel >(Channel .Email , chanel ))
3371+ .Bind (Tag .Unique ).To ((SmsChannel chanel ) => new KeyValuePair <Channel , INotificationChannel >(Channel .Sms , chanel ))
3372+ .Bind (Tag .Unique ).To ((PushChannel chanel ) => new KeyValuePair <Channel , INotificationChannel >(Channel .Push , chanel ))
3373+ .Bind <INotificationService >().To <NotificationService >()
3374+
3375+ // Composition root
3376+ .Root <INotificationService >(" NotificationService" );
3377+
3378+ var composition = new Composition ();
3379+ var notificationService = composition .NotificationService ;
3380+
3381+ // Verify that all notification channels are injected into the dictionary
3382+ notificationService .Channels .Count .ShouldBe (3 );
3383+ notificationService .Channels [Channel .Email ].ShouldBeOfType <EmailChannel >();
3384+ notificationService .Channels [Channel .Sms ].ShouldBeOfType <SmsChannel >();
3385+ notificationService .Channels [Channel .Push ].ShouldBeOfType <PushChannel >();
3386+
3387+ interface INotificationChannel
3388+ {
3389+ void Send (string message );
3390+ }
3391+
3392+ class EmailChannel : INotificationChannel
3393+ {
3394+ public void Send (string message ) => Console .WriteLine ($" Email: {message }" );
3395+ }
3396+
3397+ class SmsChannel : INotificationChannel
3398+ {
3399+ public void Send (string message ) => Console .WriteLine ($" SMS: {message }" );
3400+ }
3401+
3402+ class PushChannel : INotificationChannel
3403+ {
3404+ public void Send (string message ) => Console .WriteLine ($" Push: {message }" );
3405+ }
3406+
3407+ enum Channel { Email , Sms , Push }
3408+
3409+ interface INotificationService
3410+ {
3411+ IReadOnlyDictionary <Channel , INotificationChannel > Channels { get ; }
3412+ }
3413+
3414+ class NotificationService (IReadOnlyDictionary <Channel , INotificationChannel > channels ) : INotificationService
3415+ {
3416+ public IReadOnlyDictionary <Channel , INotificationChannel > Channels { get ; } = channels ;
3417+ }
3418+ ```
3419+
3420+ To run the above code, the following NuGet packages must be added:
3421+ - [ Pure.DI] ( https://www.nuget.org/packages/Pure.DI )
3422+ - [ Shouldly] ( https://www.nuget.org/packages/Shouldly )
3423+
3424+ > [ !NOTE]
3425+ > Dictionary injection is useful when you need to access dependencies by keys, such as named or tagged implementations like notification channels.
3426+
33613427## Lazy
33623428
33633429Demonstrates lazy injection using Lazy<T >, delaying instance creation until the Value property is accessed.
@@ -8243,6 +8309,199 @@ To run the above code, the following NuGet packages must be added:
82438309> [ !NOTE]
82448310> Splitting composition setup across multiple partial classes can improve organization for large compositions but may reduce readability if overused.
82458311
8312+ ## IsLockRequired
8313+
8314+ ` IsLockRequired ` indicates whether a lock is required for thread-safe operations in the current context. This property is useful when you need to conditionally synchronize based on thread safety requirements.
8315+
8316+ ``` c#
8317+ using Shouldly ;
8318+ using Pure .DI ;
8319+
8320+ var composition = new Composition ();
8321+
8322+ var service = composition .Service ;
8323+ service .Locked .ShouldBeTrue ();
8324+
8325+ var singletonService = composition .SingletonService ;
8326+ singletonService .Locked .ShouldBeFalse ();
8327+
8328+ interface IService
8329+ {
8330+ bool Locked { get ; }
8331+ }
8332+
8333+ class Service (bool lockRequired ) : IService
8334+ {
8335+ public bool Locked => lockRequired ;
8336+ }
8337+
8338+ partial class Composition
8339+ {
8340+ private void Setup () =>
8341+
8342+ DI .Setup (nameof (Composition ))
8343+ .Hint (Hint .ThreadSafe , " On" )
8344+ .Bind ().To (ctx =>
8345+ {
8346+ // In a thread-safe context, IsLockRequired is true
8347+ // Use it to conditionally lock the context
8348+ if (ctx .IsLockRequired )
8349+ {
8350+ lock (ctx .Lock )
8351+ {
8352+ return new Service (ctx .IsLockRequired );
8353+ }
8354+ }
8355+
8356+ return new Service (ctx .IsLockRequired );
8357+ })
8358+ .Bind (Tag .Single ).As (Lifetime .Singleton ).To ((IService service ) => service )
8359+ .Root <IService >(nameof (Service ))
8360+ .Root <IService >(nameof (SingletonService ), Tag .Single );
8361+ }
8362+ ```
8363+
8364+ To run the above code, the following NuGet packages must be added:
8365+ - [ Pure.DI] ( https://www.nuget.org/packages/Pure.DI )
8366+ - [ Shouldly] ( https://www.nuget.org/packages/Shouldly )
8367+
8368+
8369+ ## Root Name
8370+
8371+ ``` c#
8372+ using Shouldly ;
8373+ using Pure .DI ;
8374+
8375+ var composition = new Composition ();
8376+ var orderService = composition .OrderService ;
8377+ orderService .Logger .Log (" Processing order" ).ShouldContain (" OrderService" );
8378+
8379+ var paymentService = composition .PaymentService ;
8380+ paymentService .Logger .Log (" Processing payment" ).ShouldContain (" PaymentService" );
8381+
8382+ interface ILogger
8383+ {
8384+ string Log (string message );
8385+ }
8386+
8387+ interface IOrderService
8388+ {
8389+ ILogger Logger { get ; }
8390+ }
8391+
8392+ interface IPaymentService
8393+ {
8394+ ILogger Logger { get ; }
8395+ }
8396+
8397+ class Logger (string rootName ) : ILogger
8398+ {
8399+ public string Log (string message ) => $" [{rootName }] {message }" ;
8400+ }
8401+
8402+ class OrderService (ILogger logger ) : IOrderService
8403+ {
8404+ public ILogger Logger => logger ;
8405+ }
8406+
8407+ class PaymentService (ILogger logger ) : IPaymentService
8408+ {
8409+ public ILogger Logger => logger ;
8410+ }
8411+
8412+ partial class Composition
8413+ {
8414+ private void Setup () =>
8415+
8416+ DI .Setup (nameof (Composition ))
8417+ .Bind ().To (ctx => new Logger (ctx .RootName ))
8418+ .Bind ().To <OrderService >()
8419+ .Root <IOrderService >(" OrderService" )
8420+ .Bind ().To <PaymentService >()
8421+ .Root <IPaymentService >(" PaymentService" );
8422+ }
8423+ ```
8424+
8425+ To run the above code, the following NuGet packages must be added:
8426+ - [ Pure.DI] ( https://www.nuget.org/packages/Pure.DI )
8427+ - [ Shouldly] ( https://www.nuget.org/packages/Shouldly )
8428+
8429+
8430+ ## Root Type
8431+
8432+ ``` c#
8433+ using Shouldly ;
8434+ using Pure .DI ;
8435+
8436+ var composition = new Composition ();
8437+ var orderService = composition .OrderService ;
8438+ orderService .Cache .Set (" order_123" , " Order Data" );
8439+ orderService .Cache .Get (" order_123" ).ShouldBe (" Order Data" );
8440+ orderService .Cache .KeyPrefix .ShouldBe (" IOrderService" );
8441+
8442+ var inventoryService = composition .InventoryService ;
8443+ inventoryService .Cache .Set (" item_456" , " Item Data" );
8444+ inventoryService .Cache .Get (" item_456" ).ShouldBe (" Item Data" );
8445+ inventoryService .Cache .KeyPrefix .ShouldBe (" IInventoryService" );
8446+
8447+ interface ICache
8448+ {
8449+ string KeyPrefix { get ; }
8450+
8451+ void Set (string key , string value );
8452+
8453+ string Get (string key );
8454+ }
8455+
8456+ interface IOrderService
8457+ {
8458+ ICache Cache { get ; }
8459+ }
8460+
8461+ interface IInventoryService
8462+ {
8463+ ICache Cache { get ; }
8464+ }
8465+
8466+ class Cache (Type rootType ) : ICache
8467+ {
8468+ private readonly Dictionary <string , string > _data = new ();
8469+
8470+ public string KeyPrefix => rootType .Name ;
8471+
8472+ public void Set (string key , string value ) => _data [key ] = value ;
8473+
8474+ public string Get (string key ) => _data .TryGetValue (key , out var value ) ? value : string .Empty ;
8475+ }
8476+
8477+ class OrderService (ICache cache ) : IOrderService
8478+ {
8479+ public ICache Cache => cache ;
8480+ }
8481+
8482+ class InventoryService (ICache cache ) : IInventoryService
8483+ {
8484+ public ICache Cache => cache ;
8485+ }
8486+
8487+ partial class Composition
8488+ {
8489+ private void Setup () =>
8490+
8491+ DI .Setup (nameof (Composition ))
8492+ .Bind ().To (ctx => new Cache (ctx .RootType ))
8493+ .Bind ().To <OrderService >()
8494+ .Root <IOrderService >(" OrderService" )
8495+ .Bind ().To <InventoryService >()
8496+ .Root <IInventoryService >(" InventoryService" );
8497+ }
8498+ ```
8499+
8500+ To run the above code, the following NuGet packages must be added:
8501+ - [ Pure.DI] ( https://www.nuget.org/packages/Pure.DI )
8502+ - [ Shouldly] ( https://www.nuget.org/packages/Shouldly )
8503+
8504+
82468505## Thread-safe overrides
82478506
82488507Demonstrates how to create thread-safe overrides in compositions, ensuring that override operations work correctly in multi-threaded scenarios.
@@ -9778,6 +10037,7 @@ public class ClockService : IClockService, IDisposable
977810037
977910038 public void Dispose ()
978010039 {
10040+ GC .SuppressFinalize (this );
978110041 // Perform any necessary cleanup here
978210042 }
978310043}
@@ -9894,6 +10154,7 @@ public class ClockService : IClockService, IDisposable
989410154
989510155 public void Dispose ()
989610156 {
10157+ SuppressFinalize (this );
989710158 // Perform any necessary cleanup here
989810159 }
989910160}
@@ -9919,6 +10180,7 @@ public class ClockManager : IDisposable
991910180
992010181 public void Dispose ()
992110182 {
10183+ SuppressFinalize (this );
992210184 // Perform any necessary cleanup here
992310185 }
992410186}
0 commit comments