-
Notifications
You must be signed in to change notification settings - Fork 0
Tutorial
StackInjector treats dependency injection as an object itself.
A stack of automatically instantiated and injected dependencies is wrapped in a StackWrapper, of which you can call the EntryPoint() method that starts the whole logic of your application.
Everything starts from an entry point, and from that everything is instantiated and injected upon need, following a structure like in the example below:
--- example ---
|Service|
↑ ↖
|Service| |Service|
↑ ↑
|ENTRY| - Classes are services for other classes, except for the entry point, which can be considered like the "Main" of the stack.
- Service classes MUST be explicitly marked with
[Service], otherwise an exception is thrown. - injected dependencies must be explicitly marked with
[Served], otherwise they'll be left tonull. -
Injector.From<T>()accepts only a type of class/interface extendingIStackEntryPoint. -
IStackEntryPoint.EntryPoint()must return an object. If in your logic there's no return type,return null.
To start, include StackInjector in your dependencies.
Then you can start right away writing some basic code:
using StackInjector;
class MyApp
{
public static void Main (string[] args)
{
Injector.From<IMyAppBase>.Start();
}
}let's now define IMyAppBase and an implementation. Let's then add another class, IAwesomeFilter
using StackInjector;
interface IMyAppBase : IStackEntryPoint
{
int ListenForInput();
}
[Service]
class MySimpleAppBase : IMyAppBase
{
[Served]
IAwesomeFilter Filter { get; set; }
public int ListenForInput()
{
// some abstract listening logic
// listened for something! quick, filter it
Console.WriteLine( this.Filter.IsNice( input ) );
}
public object EntryPoint()
{
// your base LOGIC starts HERE
// a simple example, loop of listening for some input to manage for 100 times
for ( int i = 0; i < 100; i++ )
this.ListenForInput();
// since EntryPoint must return an object
// if you don't return anything simply return null
return null;
}
}Now, if you got it, the IAwesomeFilter implementation will look something like the following:
[Service]
class MyAwesomeFilter : IAwesomeFilter
{
public bool IsNice ( int input ) => input == 69;
}- it's not necessary to mark an entry point with
[Service]if the stack uses directly the class instead of its interface as entry point
It is possible to request a specific implementation of a class, and to override a service and change only some methods during testing.
Consider the following example:
interface IMyService
{
int SomeMethod();
int AwesomeCall();
}
[Service(Version=1.0)]
class MyBasicImplementation : IMyService
{
public int SomeMethod() => 42;
public virtual int AwesomeCall() => 127;
}
[Service(Version=2.0)]
class MyAdvancedImplementation : MyBasicImplementation
{
public override int AwesomeCall() => 128;
}When you want to specify the implementation, you can directly note the specific class property with [Served], like the following:
[Served]
MyAdvancedImplementation MyService {get; set;}Or you can change the version of the service by generically calling a target version
[Served(TargetVersion=2.0)]
IMyService MyService {get; set;}Both method will assign an instance of MyAdvancedImplementation to the field. This can also be controlled with a field specific targeting method.
- if not specified, the default version of a service is
-0.0and the default service version is0.0