In some cases, initialization of objects requires synchronization of the overall composition flow. This scenario demonstrates how to use factories with thread synchronization to ensure proper initialization order.
using Shouldly;
using Pure.DI;
DI.Setup(nameof(Composition))
.Bind<IMessageBus>().To<IMessageBus>(ctx => {
// Initialization logic requiring synchronization
// of the overall composition flow.
// For example, connecting to a message broker.
lock (ctx.Lock)
{
ctx.Inject(out MessageBus bus);
bus.Connect();
return bus;
}
})
.Bind<INotificationService>().To<NotificationService>()
// Composition root
.Root<INotificationService>("NotificationService");
var composition = new Composition();
var service = composition.NotificationService;
service.Bus.IsConnected.ShouldBeTrue();
interface IMessageBus
{
bool IsConnected { get; }
}
class MessageBus : IMessageBus
{
public bool IsConnected { get; private set; }
public void Connect() => IsConnected = true;
}
interface INotificationService
{
IMessageBus Bus { get; }
}
class NotificationService(IMessageBus bus) : INotificationService
{
public IMessageBus Bus { get; } = bus;
}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
Thread synchronization in factories should be used carefully as it may impact performance. Only use when necessary for correct initialization behavior.
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
public INotificationService NotificationService
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
IMessageBus transientIMessageBus56;
// Initialization logic requiring synchronization
// of the overall composition flow.
// For example, connecting to a message broker.
lock (_lock)
{
MessageBus localBus = new MessageBus();
localBus.Connect();
{
transientIMessageBus56 = localBus;
goto transientIMessageBus56Finish;
}
}
transientIMessageBus56Finish:
;
return new NotificationService(transientIMessageBus56);
}
}
}Class diagram:
---
config:
maxTextSize: 2147483647
maxEdges: 2147483647
class:
hideEmptyMembersBox: true
---
classDiagram
NotificationService --|> INotificationService
Composition ..> NotificationService : INotificationService NotificationService
IMessageBus *-- MessageBus : MessageBus
NotificationService *-- IMessageBus : IMessageBus
namespace Pure.DI.UsageTests.Advanced.FactoryWithThreadSynchronizationScenario {
class Composition {
<<partial>>
+INotificationService NotificationService
}
class IMessageBus {
<<interface>>
}
class INotificationService {
<<interface>>
}
class MessageBus {
<<class>>
+MessageBus()
}
class NotificationService {
<<class>>
+NotificationService(IMessageBus bus)
}
}