在Castle Windsor中,有一项称为转发类型的功能,您可以在其中为多个服务配置一个组件。例如:
var container = new WindsorContainer();
container.Register(
Component.For<Bar>().Forward<IFoo>()
.ImplementedBy<FooBar>());
var foo = container.Resolve<IFoo>();
var bar = container.Resolve<Bar>();
Debug.Assert(foo == bar);
(这个Debug.Assert有效'因为默认将Windsor注册为单例)
如何在Ninject(版本2)中实现此目的?
答案 0 :(得分:1)
我很想知道是否有其他人使用更好的解决方案,但这里有一个选项:
绑定时使用特殊的IProvider来执行前进:
public class ForwardProvider<ForwardType> : Ninject.Activation.IProvider
{
#region IProvider Members
public object Create( IContext context )
{
return context.Kernel.Get<ForwardType>();
}
public Type Type
{
get { return typeof( ForwardType ); }
}
#endregion
}
然后绑定时:
IKernel kernel = new StandardKernel();
kernel.Bind<ITestAdapter>().To<TestAdapter>().InSingletonScope();
kernel.Bind<IAnotherAdapter>().ToProvider<ForwardProvider<ITestAdapter>>();
和我的测试:
var foo = kernel.Get<ITestAdapter>();
foo.Indicator = 5;
var bar = kernel.Get<TestAdapter>();
Assert.That( foo.Indicator, Is.EqualTo( 5 ) );
var baz = kernel.Get<IAnotherAdapter>();
Assert.That( baz.Indicator, Is.EqualTo( 5 ) );
答案 1 :(得分:0)
我使用@dave thieben提供的解决方案的略微变化。或者更确切地说,根据具体情况,我使用两种不同的方法。
第一种方法与Dave基本相同,但没有创建单独的提供者。
var kernel = new StandardKernel();
kernel.Bind<FooBar>().ToSelf().InSingletonScope();
kernel.Bind<IFoo>().ToMethod(ctx => ctx.Kernel.Get<FooBar>());
kernel.Bind<IBar>().ToMethod(ctx => ctx.Kernel.Get<FooBar>());
这种方法的优点是我们可以获得通用约束的好处。但是,我们需要为每个转发类型显式创建绑定。
第二种方法更精细,涉及“劫持”流畅的界面。
var kernel = new StandardKernel();
kernel.Bind<FooBar>().ToSelf()
.Forward().As<IFoo>().As<IBar>()
.InSingletonScope();
为此,我们扩展了默认绑定构建器
public interface IBindingForwardSyntax<T> : IBindingWhenInNamedWithOrOnSyntax<T>
{
IBindingForwardSyntax<T> As<TService>();
}
public class BindingForwardBuilder<T>
: BindingBuilder<T>, IBindingForwardSyntax<T>
{
public BindingForwardBuilder(IBinding binding, IKernel kernel)
: base(binding, kernel) { }
public IBindingForwardSyntax<T> As<TForwardedType>()
{
Kernel.Bind<TForwardedType>().ToMethod(ctx =>
{
var provider = Binding.GetProvider(ctx);
if (!typeof(TForwardedType).IsAssignableFrom(provider.Type))
{
string message = string.Format(
"Invalid binding between '{0}' and '{1}'",
typeof(TForwardedType), typeof(T));
throw new InvalidOperationException(message);
}
return (TForwardedType)ctx.Kernel.Get(typeof(T));
});
return this;
}
}
最后我们添加一个扩展方法。
public static class BindingWhenInNamedWithOrOnSyntaxExtensions
{
public static IBindingForwardSyntax<T> Forward<T>(
this IBindingWhenInNamedWithOrOnSyntax<T> syntax)
{
return new BindingForwardBuilder<T>(syntax.Binding, syntax.Kernel);
}
}
这样做的好处是我们只需要显式创建一个绑定。隐式创建转发类型的绑定。然而,这带来了一个巨大的缺点:我们没有得到通用约束的好处。因此,如果我们在定义绑定时不小心,它可能会在运行时失败。