作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
使用 Ninject 是否可能和/或一个好主意? (或任何其他 IoC 容器,就此而言)创建 默认绑定(bind) 对于不存在适当实现的情况,并使用此默认绑定(bind)而不是必须处理 ActivationException
当存在多个绑定(bind)或特定请求不存在绑定(bind)时?
我一直在使用 Ninject 的 Factory和 Conventions扩展项目,但我想知道它们是否掩盖了我在更基本的层面上犯的错误,所以我创建了一个测试来说明我想要做什么,尽可能简单:
鉴于以下情况:
public interface IWidget { }
public class DefaultWidget : IWidget { }
public class BlueWidget : IWidget { }
[Fact]
public void Unknown_Type_Names_Resolve_To_A_Default_Type()
{
StandardKernel kernel = new StandardKernel();
// intention: resolve a `DefaultWidget` implementation whenever the
// 'name' parameter does not match the name of any other bound implementation
kernel.Bind<IWidget>().To<DefaultWidget>();
kernel.Bind<IWidget>().To<BlueWidget>().Named(typeof(BlueWidget).Name);
kernel.Get<IWidget>("RedWidget").Should().BeOfType<DefaultWidget>();
// ACTIVATION EXCEPTION (**NO matching bindings available** for `IWidget`)
}
BlueWidget
,以及传入的“RedWidget”字符串值的未知数量的变化。
IWidget
实现。到目前为止,我一直在使用由 Ninject.Extensions.Factory 自动创建的工厂以及自定义实例提供程序和自定义绑定(bind)生成器,但我无法解决这个问题。
IWidget
的新实现必须写,我也得打开这个工厂更新它。在我的示例中,我还必须在绑定(bind)中添加另一行 - 但这就是基于约定的绑定(bind)的用武之地,我计划使用它来避免必须不断更新绑定(bind)定义。
public interface IWidgetFactory { IWidget Create(string name); }
public class WidgetFactory : IWidgetFactory
{
private readonly IKernel kernel;
public WidgetFactory(IKernel kernel) { this.kernel = kernel; }
public IWidget Create(string name)
{
switch (name)
{
case "Blue":
return this.kernel.Get<IWidget>(typeof (BlueWidget).Name);
default:
return this.kernel.Get<IWidget>(typeof (DefaultWidget).Name);
}
}
}
[Fact]
public void WidgetBuilders_And_Customizers_And_Bindings_Oh_My()
{
StandardKernel kernel = new StandardKernel();
kernel.Bind<IWidget>().To<DefaultWidget>().Named(typeof(DefaultWidget).Name);
kernel.Bind<IWidget>().To<BlueWidget>().Named(typeof (BlueWidget).Name);
kernel.Bind<IWidgetFactory>().To<WidgetFactory>().InSingletonScope();
kernel.Get<IWidgetFactory>().Create("Blue")
.Should().BeOfType<BlueWidget>();
kernel.Get<IWidgetFactory>().Create("Red")
.Should().BeOfType<DefaultWidget>();
}
IKernel
进入IWidgetFactory
IWidget
的每个新实现, IWidgetFactory
必须更新 IWidget
的计数实现很高,“小部件名称”参数的预期范围基本上是无限的,所有无法解析的小部件名称都应使用
DefaultWidget
处理?
[Fact]
public void Unknown_Type_Names_Resolve_To_A_Default_Type()
{
StandardKernel kernel = new StandardKernel();
// evolution #1: simple as possible
// PASSES (as you would expect)
//kernel.Bind<IWidget>().To<BlueWidget>();
//kernel.Get<IWidget>().Should().BeOfType<BlueWidget>();
// evolution #2: make the only binding to a different IWidget
// FAILS (as you would expect)
//kernel.Bind<IWidget>().To<DefaultWidget>();
//kernel.Get<IWidget>().Should().BeOfType<BlueWidget>();
// evolution #3: add the binding to `BlueWidget` back
// ACTIVATION EXCEPTION (more than one binding for `IWidget`)
//kernel.Bind<IWidget>().To<DefaultWidget>();
//kernel.Bind<IWidget>().To<BlueWidget>();
//kernel.Get<IWidget>().Should().BeOfType<BlueWidget>();
// evolution #4: make `BlueWidget` binding a *named binding*
// ACTIVATION EXCEPTION (more than one binding for `IWidget`)
//kernel.Bind<IWidget>().To<DefaultWidget>();
//kernel.Bind<IWidget>().To<BlueWidget>().Named(typeof (BlueWidget).Name);
//kernel.Get<IWidget>().Should().BeOfType<BlueWidget>();
// evolution #5: change `Get<>` request to specifiy widget name
// PASSES (yee-haw!)
//kernel.Bind<IWidget>().To<DefaultWidget>();
//kernel.Bind<IWidget>().To<BlueWidget>().Named(typeof(BlueWidget).Name);
//kernel.Get<IWidget>("BlueWidget").Should().BeOfType<BlueWidget>();
// evolution #6: make `BlueWidget` binding *non-named*
// ACTIVATION EXCEPTION (**NO matching bindings available** for `IWidget`)
//kernel.Bind<IWidget>().To<DefaultWidget>();
//kernel.Bind<IWidget>().To<BlueWidget>();
//kernel.Get<IWidget>("BlueWidget").Should().BeOfType<BlueWidget>();
// evolution #7: ask for non-existance `RedWidget`, hope for `DefaultWidget`
// ACTIVATION EXCEPTION (**NO matching bindings available** for `IWidget`)
//kernel.Bind<IWidget>().To<DefaultWidget>();
//kernel.Bind<IWidget>().To<BlueWidget>();
//kernel.Get<IWidget>("RedWidget").Should().BeOfType<DefaultWidget>();
// evolution #8: make `BlueWidget` binding a *named binding* again
// ACTIVATION EXCEPTION (**NO matching bindings available** for `IWidget`)
//kernel.Bind<IWidget>().To<DefaultWidget>();
//kernel.Bind<IWidget>().To<BlueWidget>().Named(typeof(BlueWidget).Name);
//kernel.Get<IWidget>("RedWidget").Should().BeOfType<DefaultWidget>();
// evolution #9: remove `RedWidget` specification in Get<> request
// ACTIVATION EXCEPTION (back to **more than one** binding for `IWidget`)
//kernel.Bind<IWidget>().To<DefaultWidget>();
//kernel.Bind<IWidget>().To<BlueWidget>().Named(typeof(BlueWidget).Name);
//kernel.Get<IWidget>().Should().BeOfType<DefaultWidget>();
}
最佳答案
不知道这在哪里堆积,但它有效。但是,您不能传递命名参数,它仅适用于空参数。换句话说,你不能这样做:
var stuff1 = kernel.Get<IWidget>("OrangeWidget");
var stuff2 = kernel.Get<IWidget>();
IDictionary dic = new Dictionary<string, string>();
dic.Add("BlueWidget", "BlueWidget");
dic.Add("RedWidget", "RedWidget");
kernel.Bind<IWidget>().To<DefaultWidget>()
.When(x => x.Service.Name != (string)dic[x.Service.Name]);
kernel.Bind<IWidget>().To<BlueWidget>().Named("BlueWidget");
var stuff1 = kernel.Get<IWidget>("BlueWidget");
var stuff2 = kernel.Get<IWidget>();
kernel.Bind<IWidget>().To<BlueWidget>().Named("BlueWidget");
kernel.Bind<IWidget>().To<DefaultWidget>().Named("DefaultWidget");
var blueOne = kernel.Get<IWidget>("BlueWidget");
var defaultOne = kernel.Get<IWidget>("DefaultWidget");
public static class NinjectExtensions
{
public static T GetDefault<T>(this IKernel kernel)
{
return kernel.Get<T>(m => m.Name == null);
}
public static T GetNamedOrDefault<T>(this IKernel kernel, string name)
{
T result = kernel.TryGet<T>(name);
if (result != null)
return result;
return kernel.GetDefault<T>();
}
}
public static void Unknown_Type_Names_Resolve_To_A_Default_Type()
{
StandardKernel kernel = new StandardKernel();
IDictionary dic = new Dictionary<string, string>();
dic.Add("BlueWidget", "BlueWidget");
dic.Add("RedWidget", "RedWidget");
kernel.Bind<IWidget>().To<DefaultWidget>().When(x => x.Service.Name != (string)dic[x.Service.Name]);
kernel.Bind<IWidget>().To<BlueWidget>().Named("BlueWidget");
// this works!
var sup = kernel.GetNamedOrDefault<IWidget>("Not here");
var stuff1 = kernel.Get<IWidget>("BlueWidget");
var stuff2 = kernel.Get<IWidget>();
}
关于dependency-injection - 使用 Ninject 并绑定(bind)默认实现,同时避免可怕的 Service Locator 反模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16047654/
我们在 session 中存储两个对象。不知何故,来自另一个用户的对象之一被加载到另一个用户的 session 中。用户应该无权访问此特定数据,一旦他们看到它,他们就知道出了什么问题。 我们有向他提供
我现在正在使用 Firefox 5 检查我的网站,我发现字体的呈现很糟糕。 这就是 Firefox (5) 和 Chrome 之间的区别:例如,看看文本 Jeffe 是如何呈现的... 默认字体系列是
我是一名优秀的程序员,十分优秀!