roots.md
July 5, 2026 ยท View on GitHub
Roots
Sometimes you need roots for all types inherited from
using Shouldly;
using Pure.DI;
DI.Setup(nameof(Composition))
.Bind().As(Lifetime.Singleton).To<Preferences>()
// Roots can be used to register all descendants of a type as roots.
.Roots<IWindow>("{type}");
var composition = new Composition();
composition.MainWindow.ShouldBeOfType<MainWindow>();
composition.SettingsWindow.ShouldBeOfType<SettingsWindow>();
interface IPreferences;
class Preferences : IPreferences;
interface IWindow;
class MainWindow(IPreferences preferences) : IWindow;
class SettingsWindow(IPreferences preferences) : IWindow;
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 Sample
dotnet 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 run
Note
This feature is useful for plugin-style architectures where you need to expose all implementations of a base type or interface.
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
private Preferences? _singletonCompositionInOtherProject;
public SettingsWindow SettingsWindow
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
if (_singletonCompositionInOtherProject is null)
lock (_lock)
if (_singletonCompositionInOtherProject is null)
{
_singletonCompositionInOtherProject = new Preferences();
}
return new SettingsWindow(_singletonCompositionInOtherProject);
}
}
public MainWindow MainWindow
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
if (_singletonCompositionInOtherProject is null)
lock (_lock)
if (_singletonCompositionInOtherProject is null)
{
_singletonCompositionInOtherProject = new Preferences();
}
return new MainWindow(_singletonCompositionInOtherProject);
}
}
}
Class diagram:
---
config:
class:
hideEmptyMembersBox: true
---
classDiagram
Preferences --|> IPreferences
Composition ..> SettingsWindow : SettingsWindow SettingsWindow
Composition ..> MainWindow : MainWindow MainWindow
SettingsWindow o-- "Singleton" Preferences : IPreferences
MainWindow o-- "Singleton" Preferences : IPreferences
namespace Pure.DI.UsageTests.Basics.RootsScenario {
class Composition {
<<partial>>
+MainWindow MainWindow
+SettingsWindow SettingsWindow
}
class IPreferences {
<<interface>>
}
class MainWindow {
<<class>>
+MainWindow(IPreferences preferences)
}
class Preferences {
<<class>>
+Preferences()
}
class SettingsWindow {
<<class>>
+SettingsWindow(IPreferences preferences)
}
}
See also: