4

Simple Injector で依存性注入を学習しようとしているので、簡単なプログラムを作成しました。たくさんの例を調べましたが、これに似たものは見つかりませんでした。Ninjectにも同様の例があり、実装をそれ自体に自己バインドします

Bind<Samurai>().ToSelf();

しかし、単純なインジェクターで自己バインディングの例は見つかりませんでした。現状では、プログラムは正常に動作し、期待どおりの結果が得られますが、それは正しい方法ですか? プログラムは最後のコード サンプルです。

インターフェース

public interface ICar
{
    void Move(string direction, int distance);
    void Stop();
}

クラス

public class Driver
{
    private readonly ICar _car = null;

    public Driver(ICar car)
    {
        this._car = car;
    }

    public void Drive(string direction, int distance)
    {
        _car.Move(direction, distance);
    }

    public void Brake()
    {
        _car.Stop();
    }
}

実装

public class Ferrari : ICar
{
    public void Move(string direction, int distance)
    {
        Console.WriteLine("I am driving {0} really fast for {1} miles", direction, distance);
    }
    public void Stop()
    {
        Console.WriteLine("I am slamming on the brakes because I'm going too fast");
    }
}

public class Lexus : ICar
{
    public void Move(string direction, int distance)
    {
        Console.WriteLine("I am driving {0} for {1} miles", direction, distance);
    }
    public void Stop()
    {
        Console.WriteLine("I am applying the brakes");
    }
}

プログラム

class Program
{
    static void Main(string[] args)
    {
        var container = new Container();
        container.Options.AllowOverridingRegistrations = true;

        container.Register<ICar, Lexus>();
        container.Register<ICar, Ferrari>();

        container.Verify();

        var johnDoeLexus = new Driver(container.GetInstance<Lexus>());

        johnDoeLexus.Drive("North", 10);
        johnDoeLexus.Brake();

        var johnDoeFerrari = new Driver(container.GetInstance<Ferrari>());

        johnDoeFerrari.Drive("North", 10);
        johnDoeFerrari.Brake();

        Console.ReadLine();
    }
}
4

3 に答える 3

11

Simple Injector で自己バインディングを行う方法は、次の登録を使用することです。

container.Register<Samurai>();

これは次のショートカットです:

container.Register<Samurai, Samurai>();

これも次のショートカットです。

container.Register<Samurai, Samurai>(Lifestyle.Transient);

呼び出すときRegister<TService, TImplementation>。基本的にコンテナに求めているのは、 aが要求さTImplementationれるたびに を作成することです。TService

ただし、Simple Injector は明示的な登録なしで具象型 ( などSamurai) を解決できますが、ほとんどの場合、すべての型 (または少なくとも を呼び出してコンテナーから直接要求するすべての型) を明示的に登録することをお勧めしますGetInstance<Something>()。そのタイプを登録することで、Simple Injector に解決したいことを知らせることができます。これにより、Simple Injector は解決できるかどうか ( を呼び出すときにVerify()) を検証でき、Simple Injectorはそのタイプの診断分析を行うことができます。

ただし、呼び出しGetInstance<TService>には登録済みのTService. あなたのコードでは、これを行っています:

container.Register<ICar, Lexus>();
var johnDoeLexus = new Driver(container.GetInstance<Lexus>());

つまり、 を登録してICarいますが、 を解決しているのではなくICar、 を解決していLexusます。Lexusは として登録されていないためTService、Simple Injector はそのタイプについて何も認識せず、この の新しい登録を作成するだけですLexus。これは、次のようにするのと同じです。

container.Register<ICar, Lexus>();
container.Register<Lexus, Lexus>();
var johnDoeLexus = new Driver(container.GetInstance<Lexus>());

これは問題になる可能性がありますICar

container.Register<ICar, Lexus>(Lifestyle.Singleton);

var instance1 = container.GetInstance<Lexus>();
var instance2 = container.GetInstance<Lexus>();

両方の呼び出しGetInstanceで同じ (単一の) インスタンスが返されることを期待するかもしれませんが、そうではありません。Simple Injector は の新しい (一時的な) 登録を作成し、 への呼び出しごとにLexus新しいが作成されるためです。LexusGetInstance

の使用にも注意してくださいAllowOverridingRegistrations。を使用するAllowOverridingRegistrationsことは、ほとんどの場合悪い考えです。他のコンテナでは、複数回呼び出すことで同じ抽象化の型の束を登録できますがRegister、Simple Injector ではこれができません。代わりに、Simple Injector にはRegisterCollectionこのためのメソッドが含まれています。たとえば、複数の車を登録するには、次のようにします。

container.RegisterCollection<ICar>(new[] { typeof(Lexus), typeof(Ferrari) });

これらの車は次のようにリクエストできます。

var cars = container.GetAllInstances<ICar>();

または、車のコレクションを型のコンストラクターに注入できます。

public SomeType(IEnumerable<ICar> cars) {
    this.cars = cars;
}

ただし、 を使用して車のリストを登録した場合、Simple Injector はどの車を返すべきかわからないため、RegisterCollectionを使用して 1 台の車をリクエストしても失敗します。GetInstance<ICar>

API は明示的にこのように設計されており、開発者が登録でエラーを起こし、コンパイルや実行さえしても誤った結果になる可能性が低くなります。コンテナにフラグをAllowOverridingRegistrations立てると、作成された登録を置き換えることができます。これは、コンテナーの構成が複数のライブラリに分割され、複数のアプリケーションで再利用されるシナリオで役立ちます。行われた登録を上書きします。これは、この以前の登録が失われることを意味します。ほとんどの場合、実際にはこれは必要ありません。

于 2014-01-16T16:07:02.897 に答える
1

自己バインディングは、Simple Injector の暗黙の動作です。したがって、次のような行

Bind<Samurai>().ToSelf();

Simple Injector では必要ありません。

于 2014-01-16T15:50:52.960 に答える
1

この質問はもっと多いと思いますNinjectの目的は何ですか .ToSelf()

Ninject は.ToSelf()、より読みやすいバージョンとして使用します

kernel.Bind<Samurai>().To<Samurai>();

.ToSelf()冗長性が低い:

kernel.Bind<Samurai>().ToSelf();

やりたい理由.ToSelf()は、スコープの定義などのメソッドを連鎖し続けることができるようにするためです。Ninjects には暗黙的な自己バインディングがあるため.ToSelf()、スコープなどを定義する場合を除き、必要ありません。

kernel.Bind<Samurai>().ToSelf().InSingletonScope();

kernel.Bind<Samurai>().ToSelf().InThreadScope()

Simple Injector の api は異なるため、Robert Petemeier が言うように、.ToSelf()必要ありません。

container.Register<Samurai>(Lifestyle.Singleton);

依存性注入について:

を求めているのは、 をLexus求めるべきときですICar:

ICar car = container.GetInstance<ICar>()

Lexusorが必要かどうかは、Ferrari登録する具象クラスに基づいて決定ICarします。

シンプルなインジェクターは十分に文書化されています

于 2014-01-16T16:03:19.723 に答える