Ninjectを使ってみた

C#で書かれた軽量なDIコンテナNinjectをちょっとだけ使ってみました。GuiceC#版のようです。

最近バージョン2がリリースされたみたいですね。
サイト

作者のブログ

あんまりドキュメントがないのが残念ですが、コードはきれいでコンパクトにまとまっている印象です。

例にのっていたサンプルプログラムを適当に変更して実行してみました。

[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod]
public void First_step()
{
    var kernel = new StandardKernel(new WarriorModule());
    var samurai = kernel.Get<Samurai>();
    Assert.AreEqual(samurai.Attack("忍者"), "忍者を切りつけた");
}

public interface IWeapon
{
    string Hit(string target);
}

public class Sword : IWeapon
{
    public string Hit(string target)
    {
        return string.Format("{0}を切りつけた", target);
    }
}

public class Samurai
{
    private IWeapon _weapon;

    [Inject]
    public Samurai(IWeapon weapon) {
        _weapon = weapon;
    }

    public string Attack(string target)
    {
        return _weapon.Hit(target);
    }
}

public class WarriorModule : NinjectModule
{
    public override void Load()
    {
        Bind<IWeapon>().To<Sword>();
        Bind<Samurai>().ToSelf();
    }
}

Moduleは必須ではないみたい。Kernelに直接Bindできます。

[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod]
public void Bind_without_module()
{
    var kernel = new StandardKernel();
    kernel.Bind<IWeapon>().To<Sword>();
    kernel.Bind<Samurai>().ToSelf();
    var samurai = kernel.Get<Samurai>();
    Assert.AreEqual(samurai.Attack("忍者"), "忍者を切りつけた");
}

インスタンスのスコープはデフォルトだとtransientだそうです。つまり毎回つくられます。Javaだとprototypeとよんだりしますが。

[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod]
public void Bind_in_default_scope()
{
    var kernel = new StandardKernel();
    kernel.Bind<IWeapon>().To<Sword>();
    kernel.Bind<Samurai>().ToSelf();
    Assert.AreNotSame(kernel.Get<Samurai>(), kernel.Get<Samurai>());
}

singletonにするには、InSingletonScopeメソッドを呼びます。

[global::Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod]
public void Bind_in_singleton_scope()
{
    var kernel = new StandardKernel();
    kernel.Bind<IWeapon>().To<Sword>();
    kernel.Bind<Samurai>().ToSelf().InSingletonScope();
    Assert.AreSame(kernel.Get<Samurai>(), kernel.Get<Samurai>());
}