有人可以提供一个如何使用TinyIoC实现装饰器模式的简单示例吗?
之前的question显示如何在Ninject中执行以下操作:
Bind<IRepository>().To<MoreAdvancedRespository>
.WhenInjectedInto<TrickyRepository>();
Bind<IRepository>().To<SomeSimpleRepository>
.WhenInjectedInto<MoreAdvancedRespository>();
答案 0 :(得分: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
然后可以在扩展方法中包装,以便在容器上再次调用单个方法。不幸的是,这不起作用 - 在尝试解析名为“advanced”的IRepository
注册时,容器显然找不到MoreAdvancedRepository
之前的显式注册并抛出TinyIoCResolutionException
所以,如果是,上述情况将有效
- 每个不同的存储库类型仅解析一次或
- 每次解析特定的存储库类型时都会创建一个新实例。
否则你可能需要回到穷人的DI那些类或使用不同的IoC容器。
答案 1 :(得分:1)
您无法使用自动布线,因此您必须为每个装饰器注册一个lambda:
// Register the repository
container.Register<SomeSimpleRepository>();
// Register the inner decorator
container.Register<MoreAdvancedRespository>(() => new MoreAdvancedRespository(
container.Resolve<SomeSimpleRepository>(),
container.Resolve<ISomeOtherDependency>()));
// Register the outer decorator
container.Register<IRepository>(() => new TrickyRepository(
container.Resolve<MoreAdvancedRespository>(),
container.Resolve<ISomeOtherDependency>()));
您必须为系统中的每个存储库重复此操作。