ThunderboltIoc
One of the very first IoC frameworks for .Net that has no reflection. An IoC that casts its services before thunder casts its bolts.
Install / Use
/learn @AlyElhaddad/ThunderboltIocREADME
One of the very first IoC frameworks for .Net that has no reflection. An IoC that casts its services before thunder casts its bolts :smile:
The goal is to create a code-generation based IoC container for .Net. Almost all containers today rely on reflection to provide a functioning IoC, which is a costly operation. Regardless of the valued attempts to improve the performance of these containers over the years, these containers would not match the performance of a code-generation based IoC, if that could be achieved. It is quite irritating to witness the cost we pay for trying to clean our code by -among other things- using a reflection-based IoC framework and being able to do nothing about it. The idea is to let the user (the developer) write their code as they please, and let the IoC take care of code generation during compilation to provide a working and performant solution in the target assembly.
I have finally managed to find the time to start working on the solution. Fortunately for me and for the community, I read about source generators in .Net before starting. Having watched the power of source-generators combined with the power of Roslyn, I decided to pick that path over other approaches such as T4 templates and CodeDom for code generation, and I'm glad I made that choice. Mine might not be the first solution to follow this approach, but I like to think of it as the most powerful and flexible one to-date.
Below is a documentation as well as features overview and a quick-start guide to walk you through the framework. If you like my work and are looking forward to supporting me and helping me to continue to improve it, you may do that by:
I'm also open to your suggestions. Feel free to contact me on twitter @aly_elhaddad
p.s. the phrase "if that could be achieved" did exist in my original pretext in March 2021. Even though I managed to make this true today, I decided to keep it here as further motivation for the reader.
Document outline
- 1. Installation
- 2. Quick start
- 3. Features overview
- 4. Benchmarks
- 5. Service lifetimes
- 6. Service registration
- 7. How to resolve/get your instances
- 8. Supported project types
- 9. Known limitations
- 10. Planned for future versions
1. Installation
ThunderboltIoc's installation is a simple as installing the nuget to the target assemblies. No further configuration is needed. For the sake of registering your services, however, you're going to need to implement (i.e create a class that inherits) ThunderboltRegistration as a partial class in each project where you may want to register services.
You may find the package at Nuget.org:
using dotnet:
dotnet add package ThunderboltIoc
or using Nuget Package Manager Console:
Install-Package ThunderboltIoc
1.1. Make sure that you're using C# version 9.0 or later
In each of your projects where ThunderboltIoc is referenced, make sure that the C# version used is 9.0 or later. In your *.csproj add:
<PropertyGroup>
<LangVersion>9.0</LangVersion>
</PropertyGroup>
Please note that C# 9.0 is supported only in Visual Studio 2022, and Visual Studio 2019 starting from version 16.7.
1.2. Implement ThunderboltRegistration as a partial class
This step is not needed if you don't have any types/services that you would like to register in this assembly. However, if you do (which is likely), you should create a partial class that implements the ThunderboltRegistration abstract class. More on the registration can be found in the relevant section of this document.
2. Quick start
After installation, here's a minimal working example:
2.1. Anywhere in your assembly FooAssembly
public partial class FooThunderboltRegistration : ThunderboltRegistration
{
protected override void Register(IThunderboltRegistrar reg)
{
reg.AddSingleton<BazService>();
reg.AddScoped<IBarService, BarService>();
reg.AddTransientFactory<Qux>(() => new Qux());
}
}
2.2. At your startup code
Where this code may execute before any attempt to resolve/get your services.
ThunderboltActivator.Attach<FooThunderboltRegistration>();
2.3. Using your services
The simplemost way to get your services would be as follows:
BazService bazService = ThunderboltActivator.Container.Get<BazService>();
3. Features overview
- Achieving dependency injection in .Net without reflection, based on roslyn source generators, with a simple and intuitive API.
- Being able to register your services with three different lifetimes: Singleton, Scoped and Transient.
- Explicit registration where you instruct the framework to register a particular service.
- The ability to register services while specifying user-defined factories for their creation while maintaining their lifetimes.
- The ability to register services while specifying user-defined logic to determine the type of the service implementation.
- Attribute-based service registration where you can use attributes to register or exclude types.
- Registration by convention where we can register services by naming convention using regular expressions.
4. Benchmarks
The src/benchmarks project uses BenchmarkDotNet to conduct measured performance comparison between ThunderboltIoc and the following dependency injection frameworks:
-
Microsoft.Extensions.DepdendencyInjection (on nuget.org) - benchmarks legend: MicrosoftDI The industry-standard dependency injection framework for .Net provided by Microsoft that offers basic set of features at a high performance. It relies on runtime expression compilation for services creation.
-
Grace (on nuget.org) Known for its wide range of features offered at a superior performance. It depends on
System.Reflection.Emitruntime code generation for creating services.It is worth mentioning that iOS does not support runtime code generation and therefore Grace's options are limited when it comes to Xamarin apps or client-side apps in general.
-
Autofac (on nuget.org) Famous and known for its rich features. It uses raw reflection to instantiate services, but that comes at a grievous cost as the benchmarks show.
Despite being new, ThunderboltIoc attempts to combine the best of each of these frameworks and avoid the worst, with an optimum memory usage. The benchmarks run multiple times with different run strategies and measures the performance o
