This is a C# dependency injection (DI) library with a small set of features.
It is primarily developed to be used in conjunction with our other libraries. Its simple nature also makes it an easy point to start learning DI.
If you are new to DI just jump into this Unity3D tutorial project to learn its usage and advantages.
using System;
using Com.Bit34Games.Injector;
// A class that we need to access its reference in other classes
class UserData
{
public string name;
public UserData()
{
this.name = "Guest";
}
}
// A target class that will be injected into
class MyWindow
{
[Inject] private UserData _userData;
public void Show()
{
Console.WriteLine("Hello " + _userData.name);
}
}
class Program
{
static void Main(string[] args)
{
// Create injector
IInjector InjectorContext = new InjectorContext(true);
// Add bindings
UserData myUser = new UserData();
myUser.name = "It is me";
injector.AddBinding<UserData>().ToValue(myUser);
// Inject into targets
MyWindow window = new MyWindow();
injector.InjectInto(window);
// All set
window.Show();
}
}
- Only singleton bindings; every binded type will share same instance.
- Bind first, use later; after making first injection you can not make any more bindings and it will cause an error.
Constructor parameter shouldThrowException
allows you to choose error handling behavior.
When set to true
, InjectorContext
throws an exception when an error occurs. This should be your default choice for development cause it will let you find errors sooner.
When set to false
, InjectorContext
internally stores error messages for later examinations. This behavior is added for development purposes. Even though it is not advised, you can use this option on production to manually catch unexpected errors.
Binding is implemented as a fluent api to make it easy to write and read.
To add a new binding you start by calling AddBinding
generic method with the binding type that you want to inject in classes.
injector.AddBinding<MyClass>()
It returns an object with two methods.
ToValue
method allows you to bind an already instantiated provider object to binding type.
MyClass myClass = new MyClass();
injector.AddBinding<MyClass>().ToValue(myClass);
ToType
method allows you to bind a provider type that will be instantiated the first time it is needed.
injector.AddBinding<MyClass>().ToType<MyClass>();
PS: Provider type must have a parameterless constructor or a constructor that has default values for all off its parameters.
You can bind a binding type to assignable provider type or value (interface implementations to interfaces, child classes to parent classes).
Lets say you have a Setting
class that implements read only ISettings
interface.
interface ISettings
{
float Volume { get; }
}
class Settings : ISettings
{
public float Volume { get; set; }
}
You can use interface as binding type since its implementations are assignable to it.
injector.AddBinding<ISettings>().ToType<Settings>();
Actually you can bind multiple binding types to same value or provider type if they are assignable. They will share the same instance of Settings
class.
injector.AddBinding<Settings>().ToType<Settings>();
injector.AddBinding<ISettings>().ToType<Settings>();
Some uses of this practice are;
- Using read only and mutable interfaces of a type to prevent accedental writes (e.g. injecting
Settings
inSettingsWindow
, injecting readonlyISettings
interface everywhere else) - Binding platform specific implementations and to a common interface to provide abstraction (e.g. injecting IPlatform in everywhere, binding it to WindowsPlatform or LinuxPlatform implementations depending on your target)
- Using debugging friendly implementations of interfaces to find or isolate errors faster (e.g. an implementaion that adds verbose logging)
- Provide a dummy implementations of a class before its actual implementation is available (e.g. injecting IHighScoreServer, using MockHighScoreServer until it is provided )
TBA
After you complete your injections all you have to do is to using InjectInto
to target objects. This will set all fields and properties that has Inject
attribute.
injector.InjectInto(window);
injector.InjectInto(settingsPanel);
injector.InjectInto(playerManager);
Other than injections InjectorContext
has methods to access instances directly. Those are usefully for initilization methods after bindings are completed.
T GetInstance<T>()
methods gets the instance of that bindind type
injector.GetInstance<ISaveManager>().LoadSaves();
IEnumerator<T> GetAssignableInstances<T>()
method checks all provider types and values and collect if they are assignable to given type;
IEnumerator<IManager> managers = injector.GetAssignableInstances<IManager>();
while(manager.MoveNext())
{
managers.Current.Initialize();
}
When InjectorContext
is set to NOT to throw errors in constructor you can use ErrorCount
property and GetError()
method any time to inspect stored errors in InjectorContext
.