1

TinyIoCでデコレータ パターンを実装する方法の簡単な例を教えてください。

前の質問では、次のようにNinjectでこれを行う方法を示しています。

Bind<IRepository>().To<MoreAdvancedRespository>
               .WhenInjectedInto<TrickyRepository>();
Bind<IRepository>().To<SomeSimpleRepository>
               .WhenInjectedInto<MoreAdvancedRespository>();
4

2 に答える 2

2

この例をしばらく設定しようとした後、短い答えは次のとおりです。少なくとも、従来の意味で「リポジトリ」について話している場合は、TinyIoC は適切にそれを行うことができず、リポジトリによってシングルトンとして扱われることを望んでいます。容器。

そうは言っても、この種の作品:

public interface IRepository { }

public class MoreAdvancedRepository : IRepository
{
    public MoreAdvancedRepository(IRepository innerRepository, ISomeOtherDependency otherDependency) { }
}

public class TrickyRepository : IRepository
{
    public TrickyRepository(IRepository innerRepository, ISomeOtherDependency otherDependency) { }
}

public class SimpleRepository : IRepository { }

public interface ISomeOtherDependency { }

public class SomeOtherDependencyWeasel : ISomeOtherDependency { }


// Register the other dependency
container.Register<ISomeOtherDependency, SomeOtherDependencyWeasel>();

// Register the "innermost" repository with a name
container.Register<IRepository, SimpleRepository>("simple");

// Register the inner decorator implementation, also with a name, and telling the container what to do for the dependency called "innerRepository"
container.Register<IRepository>((c, p) => c.Resolve<MoreAdvancedRepository>(new NamedParameterOverloads() { { "innerRepository", c.Resolve<IRepository>("simple") } }), "advanced");

// Register the outer decorator the same way, only without a name for the registration, so this will be what's resolved whenever IRepository is requested without specifying a name
container.Register<IRepository>((c, p) => c.Resolve<TrickyRepository>(new NamedParameterOverloads() { { "innerRepository", c.Resolve<IRepository>("advanced") } }));

// Resolve stuff to check how the registration worked out
var simple1 = container.Resolve<IRepository>("simple");
var simple2 = container.Resolve<IRepository>("simple");
var advanced1 = container.Resolve<IRepository>("advanced");
var advanced2 = container.Resolve<IRepository>("advanced");
var tricky1 = container.Resolve<IRepository>();
var tricky2 = container.Resolve<IRepository>();

Assert.IsType<SimpleRepository>(simple1); // this passes, unsurprisingly
Assert.Same(simple1, simple2); // this passes, too, as simple Register<TResolve, TImpl>() calls are implicitly .AsSingleton()
Assert.IsType<MoreAdvancedRepository>(advanced1); // passes
Assert.IsType<TrickyRepository>(tricky1); // passes

Assert.Same(advanced1, advanced2); // this fails, as Register<TResolve>(Func<TResolve, TinyIoCContainer, NamedParameterOverloads>) calls are implicitly .AsMultiInstance() and can not be changed to .AsSingleton() 
Assert.Same(tricky1, tricky2); // fails for the same reason

ここで、次のようにしてコンテナーをだまそうとする誘惑に駆られるかもしれません (私はそうでした)。

container.Register<MoreAdvancedRepository>((c, p) => c.Resolve<MoreAdvancedRepository>(new NamedParameterOverloads() { { "innerRepository", c.Resolve<IRepository>("simple") } })); // always .AsMultiInstance()

container.Register<IRepository, MoreAdvancedRepository>("advanced"); // implicitly .AsSingleton(), so only one instance should be created and then returned for subsequent calls

これを拡張メソッドにラップして、コンテナーで単一のメソッド呼び出しを再度行うことができます。残念ながら、これは機能しませんIRepository。「advanced」という名前の登録を解決しようとしているときに、コンテナーは明らかに以前の明示的な登録を見つけられずMoreAdvancedRepositoryTinyIoCResolutionException.

したがって、上記は
、異なるリポジトリ タイプがそれぞれ 1 回だけ解決されるか
、特定のリポジトリ タイプが解決されるたびに新しいインスタンスが作成されても問題ない場合に機能します。

それ以外の場合は、おそらくそれらのクラスの貧弱な DI にフォールバックするか、別の IoC コンテナーを使用する必要があります。

于 2013-07-12T22:33:19.510 に答える