Demonstrates how disposable instances created within delegate factories are tracked and disposed properly when the composition is disposed.
using Shouldly;
using Pure.DI;
var composition = new Composition();
var transaction1 = composition.Transaction;
var transaction2 = composition.Transaction;
transaction2.Dispose();
// Checks that the disposable instances
// associated with transaction2 have been disposed of
transaction2.Connection.IsDisposed.ShouldBeTrue();
// Checks that the disposable instances
// associated with transaction1 have not been disposed of
transaction1.Connection.IsDisposed.ShouldBeFalse();
transaction1.Dispose();
// Checks that the disposable instances
// associated with transaction1 have been disposed of
transaction1.Connection.IsDisposed.ShouldBeTrue();
interface IDbConnection
{
bool IsDisposed { get; }
}
class DbConnection : IDbConnection, IDisposable
{
public bool IsDisposed { get; private set; }
public void Dispose() => IsDisposed = true;
}
interface ITransaction
{
IDbConnection Connection { get; }
}
class Transaction(Func<Owned<IDbConnection>> connectionFactory)
: ITransaction, IDisposable
{
private readonly Owned<IDbConnection> _connection = connectionFactory();
public IDbConnection Connection => _connection.Value;
public void Dispose() => _connection.Dispose();
}
partial class Composition
{
static void Setup() =>
DI.Setup()
.Bind().To<DbConnection>()
.Bind().To<Transaction>()
// Composition root
.Root<Transaction>("Transaction");
}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
Disposable tracking in delegates ensures proper cleanup even when instances are created dynamically through factory delegates.
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 Transaction Transaction
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
var perBlockOwned162 = new Owned();
Func<Owned<IDbConnection>> perBlockFunc161 = new Func<Owned<IDbConnection>>(
[MethodImpl(MethodImplOptions.AggressiveInlining)]
() =>
{
Owned<IDbConnection> perBlockOwned163;
// Creates the owner of an instance
Owned transientOwned164;
Owned localOwned5 = perBlockOwned162;
transientOwned164 = localOwned5;
lock (_lock)
{
perBlockOwned162.Add(transientOwned164);
}
IOwned localOwned4 = transientOwned164;
var transientDbConnection165 = new DbConnection();
lock (_lock)
{
perBlockOwned162.Add(transientDbConnection165);
}
IDbConnection localValue9 = transientDbConnection165;
perBlockOwned163 = new Owned<IDbConnection>(localValue9, localOwned4);
lock (_lock)
{
perBlockOwned162.Add(perBlockOwned163);
}
return perBlockOwned163;
});
return new Transaction(perBlockFunc161);
}
}
}Class diagram:
---
config:
maxTextSize: 2147483647
maxEdges: 2147483647
class:
hideEmptyMembersBox: true
---
classDiagram
Owned --|> IOwned
DbConnection --|> IDbConnection
Transaction --|> ITransaction
Composition ..> Transaction : Transaction Transaction
Transaction o-- "PerBlock" FuncᐸOwnedᐸIDbConnectionᐳᐳ : FuncᐸOwnedᐸIDbConnectionᐳᐳ
FuncᐸOwnedᐸIDbConnectionᐳᐳ o-- "PerBlock" OwnedᐸIDbConnectionᐳ : OwnedᐸIDbConnectionᐳ
OwnedᐸIDbConnectionᐳ *-- Owned : IOwned
OwnedᐸIDbConnectionᐳ *-- DbConnection : IDbConnection
namespace Pure.DI {
class IOwned {
<<interface>>
}
class Owned {
<<class>>
}
class OwnedᐸIDbConnectionᐳ {
<<struct>>
}
}
namespace Pure.DI.UsageTests.Advanced.TrackingDisposableInDelegatesScenario {
class Composition {
<<partial>>
+Transaction Transaction
}
class DbConnection {
<<class>>
+DbConnection()
}
class IDbConnection {
<<interface>>
}
class ITransaction {
<<interface>>
}
class Transaction {
<<class>>
+Transaction(FuncᐸOwnedᐸIDbConnectionᐳᐳ connectionFactory)
}
}
namespace System {
class FuncᐸOwnedᐸIDbConnectionᐳᐳ {
<<delegate>>
}
}