Pygmalions.Nebula.Injecting 0.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Pygmalions.Nebula.Injecting --version 0.1.0                
NuGet\Install-Package Pygmalions.Nebula.Injecting -Version 0.1.0                
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="Pygmalions.Nebula.Injecting" Version="0.1.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Pygmalions.Nebula.Injecting --version 0.1.0                
#r "nuget: Pygmalions.Nebula.Injecting, 0.1.0"                
#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.
// Install Pygmalions.Nebula.Injecting as a Cake Addin
#addin nuget:?package=Pygmalions.Nebula.Injecting&version=0.1.0

// Install Pygmalions.Nebula.Injecting as a Cake Tool
#tool nuget:?package=Pygmalions.Nebula.Injecting&version=0.1.0                

Nebula Injecting

Fundamental library of Pygmalions' Nebula Framework.

This library provides an implementation of IoC mechanism. It supports intrusive injection (attribute), and non-intrusive injection (preset). The Source mechanism allows you to merge presets defined in data sources (SQL, XML, JSON, etc) into the containers.

Concepts

Preset

Preset is a data class, which describes how to inject an object instance. You can preset the values of fields, properties, and method invocations in presets, then they will be injected into the instance when the object instance is acquired by a builder or a container.

Builder

Builder is a data class which describes how to create an object instance. Its like a Func<object?>, but the procedure of binding constructor arguments and binding class can be separately customized.

Container

Container is a set of presets and sources. A preset can describe an object with an optional name, which can be acquired by users using Get method, or be used to inject another object.

Source

Compared to builder, source is a more complex instance creator, which following a customized rule to generate instance. You need to inherit and override OnInstall, OnUninstall, and Get to make your customized source.

Source has to declare a resource before anyone want to get it from the container. A declaration instructs the container to find and use the specific source which provides this object.

When source is uninstalling from the container, all its declarations will be revoked.

It is used to introduce outsides data source into the container. For example, you can make a source which reads XML files, and declares objects which are described in the XML files in the container. When your source is invoked for getting those objects, it can generate instances according to the construction and injection information in the XML files.

You can declare an object at any time. It is common but not must to make declarations during the installing.

Name of Objects

All objects in the container have an optional name. When trying to get an object, you can also specific the name of the object to get.

There are two specific names: "" (Empty), and "*".

No matter what the specific name is, any requirement will firstly match the preset entries which has complete the same name, such "" → "", * → *, "aName" → "aName".

When the container can not find a entry with the same name, then, the container will try to find the entry with the name "*", and use it; if it fails, then it will return a null, unless the name of the requirement is "", which will let the container to use any existing entry in the same type category.

So, declare or preset an object with the name "*", if you want to make it a generator; require an object with the name "", if you only care about the type and don't care about which object to use;

And, declare or preset an object with the name "", if you want to make it the default instance for requirement which has the name "".

Injection Styles

  • Preset Injection: it is the non-intrusive style which uses a preset to instruct the container to inject an instance.
  • Passive Injection: it is the intrusive style by marking [Injection] attribute on members.

How to use

Sample Object for Injection

This is the object class which we will use to show how to use this library:

public class SampleObject
{
    public int SampleField;
    
    public int SampleProperty { get; set; }

    public int MethodValue;
    
    public void SampleMethod(int value)
    {
        MethodValue = value;
    }

    public int ConstructorValue;
    
    public SampleObject()
    {
        SampleField = -1;
        SampleProperty = -1;
        MethodValue = -1;
        ConstructorValue = -1;
    }
    
    public SampleObject(int value)
    {
        SampleField = -1;
        SampleProperty = -1;
        MethodValue = -1;
        ConstructorValue = value;
    }
}

Use a preset and a builder separately

This code will set the SampleFiled to 1, SampleProperty to 2, and invoke the SampleMethod with a parameter 3.

var instance = new Preset(typeof(SampleObject))
            .PresetField("SampleField", () => 1)
            .PresetProperty("SampleProperty", () => 2)
            .InvokeMethod("SampleMethod", () => new object?[] { 3 })
            .SetBuilder()
            .AsBuilder()?.Build() as SampleObject;

Invoke the BindArguments method of a builder will enable the constructor injection:

var instance = new Preset(typeof(SampleObject))
            .PresetField("SampleField", () => 1)
            .PresetProperty("SampleProperty", () => 2)
            .InvokeMethod("SampleMethod", () => new object?[] { 3 })
            .SetBuilder()
            .AsBuilder()?
            .BindArguments(() => new object?[]{4})
            .Build() as SampleObject;

Use a container in preset injection

It is quite similar to use a preset directly:

var container = new Container();
var instance = container.Preset<SampleObject>()
            .PresetField("SampleField", () => 1)
            .PresetProperty("SampleProperty", () => 2)
            .InvokeMethod("SampleMethod", () => new object?[] { 3 })
            .SetBuilder()
            .AsBuilder()?
            .BindArguments(() => new object?[] {4})
            .Build() as SampleObject;

Or, you can get it from the container, rather than directly invoke the builder. But actually it the same to invoking the builder.

var container = new Container();
container.Preset<SampleObject>()
    .PresetField("SampleField", () => 1)
    .PresetProperty("SampleProperty", () => 2)
    .InvokeMethod("SampleMethod", () => new object?[] { 3 })
    .SetBuilder()
    .AsBuilder()?
    .BindArguments(() => new object?[] {4});
var instance = container.Get<SampleObject>() as SampleObject;

Sample Object for Passive Injection

Compared to SampleObject, this class has [Injection] on members.

public class PassiveSampleObject
{
    [Injection("SampleField")]
    public int SampleField;
    
    [Injection("SampleProperty")]
    public int SampleProperty { get; set; }

    public int MethodValue;
    
    [Injection]
    public void SampleMethod([Injection("SampleMethod")] int value)
    {
        MethodValue = value;
    }

    public int ConstructorValue;
    
    public PassiveSampleObject()
    {
        SampleField = -1;
        SampleProperty = -1;
        MethodValue = -1;
        ConstructorValue = -1;
    }
    
    [Injection]
    public PassiveSampleObject([Injection("SampleConstructor")] int value)
    {
        SampleField = -1;
        SampleProperty = -1;
        MethodValue = -1;
        ConstructorValue = value;
    }
}

Use a container for passive injection

Invoke the builder:

var container = new Container();
container.Preset<int>("SampleField").SetBuilder().AsBuilder()?
    .BindInstance(1);
container.Preset<int>("SampleProperty").SetBuilder().AsBuilder()?
    .BindInstance(2);
container.Preset<int>("SampleMethod").SetBuilder().AsBuilder()?
    .BindInstance(3);
container.Preset<int>("SampleConstructor").SetBuilder().AsBuilder()?
    .BindInstance(4);
var instance = container.Preset<PassiveSampleObject>()
    .SetBuilder()
    .AsBuilder()?
    .Build() as PassiveSampleObject;

or use the Get:

var container = new Container();
container.Preset<int>("SampleField").SetBuilder().AsBuilder()?
    .BindInstance(1);
container.Preset<int>("SampleProperty").SetBuilder().AsBuilder()?
    .BindInstance(2);
container.Preset<int>("SampleMethod").SetBuilder().AsBuilder()?
    .BindInstance(3);
container.Preset<int>("SampleConstructor").SetBuilder().AsBuilder()?
    .BindInstance(4);
container.Preset<PassiveSampleObject>().SetBuilder();
var instance = container.Get<PassiveSampleObject>() as PassiveSampleObject;

Remarks

Attention

There are two things you should be aware of:

  1. Container is necessary in passive injection.
  2. To preset a language built-in value (such as int, bool, float, etc), you must use BindInstance for these types don't have any constructors.

Unstable API

This library is under rapid development, thus its API may be very unstable, DO NOT use it in the production environment, until its version reaches 1.0.0.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
0.2.2 472 4/10/2022
0.2.1 397 4/1/2022
0.2.0 390 3/30/2022
0.1.0 414 3/27/2022

This library under rapid development, thus its API may be unstable. It is not recommended to use this library in production until the version of this library reaches 1.0.0.