Skip to content

Commit 3d27929

Browse files
Updaate README
1 parent 1491dfc commit 3d27929

111 files changed

Lines changed: 1815 additions & 825 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3358,6 +3358,72 @@ In addition to arrays, other collection types are also supported, such as:
33583358
- System.Collections.Immutable.IImmutableStack<T>
33593359
And 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

33633429
Demonstrates 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

82488507
Demonstrates 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
}

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ dotnet run
334334
- [Enumerable](readme/enumerable.md)
335335
- [Enumerable generics](readme/enumerable-generics.md)
336336
- [Array](readme/array.md)
337+
- [Dictionary](readme/dictionary.md)
337338
- [Lazy](readme/lazy.md)
338339
- [Task](readme/task.md)
339340
- [ValueTask](readme/valuetask.md)
@@ -415,6 +416,9 @@ dotnet run
415416
- [Light roots](readme/light-roots.md)
416417
- [Partial class](readme/partial-class.md)
417418
- [A few partial classes](readme/a-few-partial-classes.md)
419+
- [IsLockRequired](readme/islockrequired.md)
420+
- [Root Name](readme/root-name.md)
421+
- [Root Type](readme/root-type.md)
418422
- [Thread-safe overrides](readme/thread-safe-overrides.md)
419423
- [Override depth](readme/override-depth.md)
420424
- [Consumer types](readme/consumer-types.md)
@@ -2020,7 +2024,7 @@ AI needs to understand the situation it’s in (context). This means knowing det
20202024
| --------------- | ---- | ------ |
20212025
| [AGENTS_SMALL.md](AGENTS_SMALL.md) | 52KB | 13K |
20222026
| [AGENTS_MEDIUM.md](AGENTS_MEDIUM.md) | 100KB | 25K |
2023-
| [AGENTS.md](AGENTS.md) | 365KB | 93K |
2027+
| [AGENTS.md](AGENTS.md) | 373KB | 95K |
20242028

20252029
For different IDEs, you can use the _AGENTS.md_ file as is by simply copying it to the root directory. For use with _JetBrains Rider_ and _Junie_, please refer to [these instructions](https://www.jetbrains.com/help/junie/customize-guidelines.html). For example, you can copy any _AGENTS.md_ file into your project (using _Pure.DI_) as _.junie/guidelines.md._
20262030
## How to contribute to Pure.DI

readme/SingletonDetails.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ partial class Singleton
7979
{
8080
private readonly Singleton _root;
8181

82-
private Service1? _scopedService149;
83-
private Service4? _scopedService452;
82+
private Service1? _scopedService160;
83+
private Service4? _scopedService463;
8484

8585
[OrdinalAttribute(256)]
8686
public Singleton()
@@ -96,20 +96,20 @@ partial class Singleton
9696
[MethodImpl(MethodImplOptions.AggressiveInlining)]
9797
public partial CompositionRoot TestPureDIByCR()
9898
{
99-
if (_scopedService149 is null)
99+
if (_scopedService160 is null)
100100
{
101101
EnsureService4Exists();
102-
_scopedService149 = new Service1(new Service2(new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452)));
102+
_scopedService160 = new Service1(new Service2(new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463)));
103103
}
104104

105105
EnsureService4Exists();
106-
return new CompositionRoot(_scopedService149, new Service2(new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452)), new Service2(new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452)), new Service2(new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452), new Service3(_scopedService452, _scopedService452)), new Service3(_scopedService452, _scopedService452), _scopedService452, _scopedService452);
106+
return new CompositionRoot(_scopedService160, new Service2(new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463)), new Service2(new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463)), new Service2(new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463), new Service3(_scopedService463, _scopedService463)), new Service3(_scopedService463, _scopedService463), _scopedService463, _scopedService463);
107107
[MethodImpl(MethodImplOptions.AggressiveInlining)]
108108
void EnsureService4Exists()
109109
{
110-
if (_scopedService452 is null)
110+
if (_scopedService463 is null)
111111
{
112-
_scopedService452 = new Service4();
112+
_scopedService463 = new Service4();
113113
}
114114
}
115115
}

0 commit comments

Comments
 (0)