Resolver 1.0.4

dotnet add package Resolver --version 1.0.4
                    
NuGet\Install-Package Resolver -Version 1.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Resolver" Version="1.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Resolver" Version="1.0.4" />
                    
Directory.Packages.props
<PackageReference Include="Resolver" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Resolver --version 1.0.4
                    
#r "nuget: Resolver, 1.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Resolver@1.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Resolver&version=1.0.4
                    
Install as a Cake Addin
#tool nuget:?package=Resolver&version=1.0.4
                    
Install as a Cake Tool

Resolver

Resolver helps you write loosely coupled code that is easy to change, compose and test. The library is easy to adopt, works with .NET Standard and exposes a concise syntax.

Read more about Dependency Injection.

Get Started

Available on NuGet: Resolver

NuGet Package Manager: Install-Package Resolver

Contents

  • Resolver Can register a new dependency, build new objects and resolve their dependencies.
  • Resolvable Attribute to be used on properties that will automatically be resolved.

Usage

Resolver is intended to be used as an singleton. However, that decision belongs to the consumer.

var resolver = new Resolver();

Register

Once you build you a Resolver, you can use it to register dependencies:

ISoundService soundService = new SoundService();
resolver.Register(soundService);

Resolve

After you register a property, you can resolve objects that contain properties of the same type as the registered dependencies.

class PageViewModel
{
    public ISoundService Sound { get; set; }
}

var viewModel = resolver.Resolve<PageViewModel>();

At this point, Sound property of the viewModel object has been populated with soundService object.

Notice: Resolve only creates new objects, but no new dependencies.

E.g.:

var viewModel1 = resolver.Resolve<PageViewModel>();
var viewModel2 = resolver.Resolve<PageViewModel>();

viewModel1.Sound is equal to viewModel2.Sound by pointing to the same reference soundService.

[Resolvable]

Resolvable attribute can be use on any property that will have to be instantiated at runtime.

class ControlViewModel
{
}

class NavigationViewModel
{
    [Resolvable]
    public ControlViewModel Control { get; set; }
}

var navigation = resolver.Resolve<NavigationViewModel>();

At this point navigation.Control has been instantiated and can therefore be used.

Registered dependencies vs. [Resolvable] properties

As you have seen above, the main difference between a registered dependency and a [Resolvable] property is their lifetime and their relation to their owner.

  • Registered dependencies have a longer lifetime than the objects that consume them. E.g.: a SoundService can outlive different app pages.

  • [Resolvable] properties are have a shorter or equal lifetime than their owner's. E.g.: a property CreateAccountView only makes sense on a Start page, therefore there is no need to keep it around longer that the Start page.

Finally, registered dependencies and [Resolvable] can be used in the same class, and the Resolve method with figure out how to handle each according to the rules mentioned above. Furthermore, the newly instantiated [Resolvable] property follows the same Resolve logic, meaning that any further dependencies it has will be resolved as well (either registered or [Resolvable])

class ControlViewModel
{
    public ISoundService Sound { get; set; }
}

class NavigationViewModel
{
    [Resolvable]
    public ControlViewModel Control { get; set; }

    public ISoundService Sound { get; set; }
}

var navigation = resolver.Resolve<NavigationViewModel>();

At this point navigation.Control has been instantiated, and both navigation.Sound and navigation.Control.Sound point to the same reference, soundService.

Performance

Resolver uses Reflection to inspect types and create objects. While Reflection is a powerful library, it does come with some performance penalty. There are numerous resources where you can find more details about how fast Refection build objects, and Resolver's performance will follow Reflection's performance.

Here are tests performed on a DEBUG build that create 10.000 objects using instantiation and Resolve.

  • Scenario 1: No registered or [Resolvable] properties
Instantiate 10.000 objects Resolve 10.000 objects
< 1 ms 20 ms
  • Scenario 2: registered dependencies
Instantiate 10.000 objects Resolve 10.000 objects
1 dependency < 1 ms 5 ms
10 dependencies 4 ms 175 ms
  • Scenario 3: [Resolvable] properties
Instantiate 10.000 objects Resolve 10.000 objects
1 dependency < 1 ms 50 ms
10 dependencies 4 ms 400 ms

The performance penalty is noticeable when creating a large number of objects, especially when using [Resolvable] properties. That is because Reflection needs to assign and / or instantiate (number of objects) * (number of dependencies).

In real world scenarios, general purpose apps tend to have smaller object hierarchies making the use of DI acceptable. In most cases even objects with a complex hierarchy or multiple levels of child objects can be resolved in less than 1 ms.

While analyzing CPU performance in real world app usage the cumulative CPU time spend by Resolver accounts for less than 1% of the total time spend on high activity scenarios that require creating new objects.

Why use Resolver

Several other platforms implement Dependency Injection for .NET. Some of the most popular ones include: Ninject, Castle Windsor.

Resolver is meant to be simple and easy to understand.

The Resolver class contains less than 160 lines of code. GetNewObject and ResolveObjectProperties, the code methods of the framework represent less than half the implementation of the Resolver class.

The conciseness of the implementation makes it a good candidate for consumers looking for either a lightweight or an easy to understand DI implementation.

Apps using Resolver

I built Resolver out of necessity, after passing dependencies via constructors got out of hand and after I learned about Dependency Injection.

It has since simplified my code, allowed me to focus on the actual logic instead of infrastructure code and ultimately helped me ship faster and better apps.

I used Resolver in several of my games published in Microsoft Store, check them out at http://frenzygames.net

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.4 212 6/23/2023
1.0.3 533 2/2/2022
1.0.2 527 5/21/2020
1.0.1 544 3/15/2020
1.0.0 577 3/15/2020