Ninject 工厂扩建
Ninject Factory Extension
我在思考 Ninject 工厂扩展时遇到了一些麻烦。
我有以下class结构
public class Resource
{
public IResourceLoader ResourceLoader {get;set;}
public Resource(IResourceLoader ResourceLoader)
{
this.ResourceLoader = ResourceLoader ;
}
}
public class Banner : Resource
{
public Banner([Named("pngLoader")] IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
public class MetaData : Resource
{
public MetaData ([Named("xmlLoader") IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
interface IResourceLoader
{
object resource {get;}
}
public class XMLLoader : IResourceLoader
{
public resource { return "this was sent by xml loader"; }
}
public class PNGLoader : IResourceLoader
{
public resource { return "this was sent by png loader"; }
}
我正在尝试根据 Named 属性实现基于约定的过滤,如 here 所示。于是我实现了如下接口
interface IResourceLoaderFactory
{
IResourceLoader GetxmlLoader();
IResourceLoader GetpngLoader()
}
然后我在依赖项解析器中的绑定看起来像
kernel.Bind<IResourceLoader>().To<XMLLoader>().NamedLikeFactoryMethod((IResourceLoaderFactory f) => f.GetxmlLoader());
kernel.Bind<IResourceLoader>().To<PNGLoader>().NamedLikeFactoryMethod((IResourceLoaderFactory f) => f.GetpngLoader());
假设以上是正确的,我不知道如何继续使用它,以便 Ninject 根据传递给 Banner 或 MetaData 的构造函数中的 [Named] 为 Banner 或 MetaData 提供正确的 IResourceLoader基础构造函数。
我在像
这样的 mvc 5 应用程序中使用所有这些
public class HomeController
{
public ActionResult Index(/* do banners and meta need to be asked for here? */)
{
/* or do I need to instantiate them here/? */
Banner banner = new Banner(/* what to put here? */);
Meta meta = new Meta(/* what to put here? */);
...
}
}
谢谢
让我尝试回答您的问题,我不是 100% 确定我已经正确理解您的问题,所以如果我没有正确理解您的问题,请给我反馈。
现在,您的基本问题是您想要注入一个 IResourceLoader
- 但根据您注入的内容,它应该是 XMLLoader
或 PNGLoader
。
您已经正确地将命名绑定识别为一种可能的解决方案,用于选择合适的 IResourceLoader
。
但是,您不需要组合 NamedLikeFactory
和 [Named]
-Attribute 模式来实现您想要的,其中一个就足够了,这里是 [Named]
-Attribute可能是两者中更好的选择(我稍后会谈到第三种)。
所以这就是你要做的:
public const string XmlLoaderName = "XmlLoader";
public const string PngLoaderName = "PngLoader";
Bind<IResourceLoader>().To<XMLLoader>()
.Named(XmlLoaderName);
Bind<IResourceLoader>().To<PNGLoader>()
.Named(PngLoaderName);
然后在构造函数中指定适当的类型(就像您所做的那样):
public class Banner : Resource
{
public Banner([Named(pngLoaderName)] IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
public class MetaData : Resource
{
public MetaData ([Named(xmlLoaderName) IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
基本上就是这样!
现在要在您的控制器中使用它,您所要做的就是:
public class HomeController
{
public HomeController(Banner baner, MetaData metaData)
{
...
}
}
无需使用工厂。除了,如果您需要为每个请求实例化一个 Banner
或 MetaData
实例,在这种情况下您将创建一个工厂接口:
public interface IResourceFactory
{
Banner CreateBanner();
MetaData CreateMetaData();
}
绑定如下:
Bind<IResourceFactory>().ToFactory();
// ToFactory is an extension method from Ninject.Extensions.Factory
将像这样使用:
public class HomeController
{
private readonly IResourceFactory resourceFactory;
public HomeController(IResourceFactory resourceFactory)
{
this.resourceFactory = resourceFactory;
}
public ActionResult Index()
{
var banner = this.resourceFactory.CreateBanner();
....
}
}
Named
绑定的替代方法:您还可以使用条件绑定,例如:
Bind<IResourceLoader>().To<XMLLoader>()
.WhenInjectedInto<Banner>();
和对应的Banner
ctor:
public Banner(IResourceLoader resourceLoader)
{
...
}
如果有一组非常有限的 类 可以注入 ResourceLoader,则此替代方案可能有意义。或者,如果您无法向构造函数添加 [Named]
-Attribute(例如因为它是第三方库...)。
另一种选择是提供 Ninject 更多关于如何构造类型的信息。例如:
Bind<Banner>().ToSelf()
.WithConstructorArgument(
typeof(IResourceLoader),
ctx => ctx.Kernel.Get<XmlLoader>());
我在思考 Ninject 工厂扩展时遇到了一些麻烦。
我有以下class结构
public class Resource
{
public IResourceLoader ResourceLoader {get;set;}
public Resource(IResourceLoader ResourceLoader)
{
this.ResourceLoader = ResourceLoader ;
}
}
public class Banner : Resource
{
public Banner([Named("pngLoader")] IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
public class MetaData : Resource
{
public MetaData ([Named("xmlLoader") IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
interface IResourceLoader
{
object resource {get;}
}
public class XMLLoader : IResourceLoader
{
public resource { return "this was sent by xml loader"; }
}
public class PNGLoader : IResourceLoader
{
public resource { return "this was sent by png loader"; }
}
我正在尝试根据 Named 属性实现基于约定的过滤,如 here 所示。于是我实现了如下接口
interface IResourceLoaderFactory
{
IResourceLoader GetxmlLoader();
IResourceLoader GetpngLoader()
}
然后我在依赖项解析器中的绑定看起来像
kernel.Bind<IResourceLoader>().To<XMLLoader>().NamedLikeFactoryMethod((IResourceLoaderFactory f) => f.GetxmlLoader());
kernel.Bind<IResourceLoader>().To<PNGLoader>().NamedLikeFactoryMethod((IResourceLoaderFactory f) => f.GetpngLoader());
假设以上是正确的,我不知道如何继续使用它,以便 Ninject 根据传递给 Banner 或 MetaData 的构造函数中的 [Named] 为 Banner 或 MetaData 提供正确的 IResourceLoader基础构造函数。
我在像
这样的 mvc 5 应用程序中使用所有这些public class HomeController
{
public ActionResult Index(/* do banners and meta need to be asked for here? */)
{
/* or do I need to instantiate them here/? */
Banner banner = new Banner(/* what to put here? */);
Meta meta = new Meta(/* what to put here? */);
...
}
}
谢谢
让我尝试回答您的问题,我不是 100% 确定我已经正确理解您的问题,所以如果我没有正确理解您的问题,请给我反馈。
现在,您的基本问题是您想要注入一个 IResourceLoader
- 但根据您注入的内容,它应该是 XMLLoader
或 PNGLoader
。
您已经正确地将命名绑定识别为一种可能的解决方案,用于选择合适的 IResourceLoader
。
但是,您不需要组合 NamedLikeFactory
和 [Named]
-Attribute 模式来实现您想要的,其中一个就足够了,这里是 [Named]
-Attribute可能是两者中更好的选择(我稍后会谈到第三种)。
所以这就是你要做的:
public const string XmlLoaderName = "XmlLoader";
public const string PngLoaderName = "PngLoader";
Bind<IResourceLoader>().To<XMLLoader>()
.Named(XmlLoaderName);
Bind<IResourceLoader>().To<PNGLoader>()
.Named(PngLoaderName);
然后在构造函数中指定适当的类型(就像您所做的那样):
public class Banner : Resource
{
public Banner([Named(pngLoaderName)] IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
public class MetaData : Resource
{
public MetaData ([Named(xmlLoaderName) IResourceLoader ResourceLoader)
:base(ResourceLoader)
{ }
}
基本上就是这样!
现在要在您的控制器中使用它,您所要做的就是:
public class HomeController
{
public HomeController(Banner baner, MetaData metaData)
{
...
}
}
无需使用工厂。除了,如果您需要为每个请求实例化一个 Banner
或 MetaData
实例,在这种情况下您将创建一个工厂接口:
public interface IResourceFactory
{
Banner CreateBanner();
MetaData CreateMetaData();
}
绑定如下:
Bind<IResourceFactory>().ToFactory();
// ToFactory is an extension method from Ninject.Extensions.Factory
将像这样使用:
public class HomeController
{
private readonly IResourceFactory resourceFactory;
public HomeController(IResourceFactory resourceFactory)
{
this.resourceFactory = resourceFactory;
}
public ActionResult Index()
{
var banner = this.resourceFactory.CreateBanner();
....
}
}
Named
绑定的替代方法:您还可以使用条件绑定,例如:
Bind<IResourceLoader>().To<XMLLoader>()
.WhenInjectedInto<Banner>();
和对应的Banner
ctor:
public Banner(IResourceLoader resourceLoader)
{
...
}
如果有一组非常有限的 类 可以注入 ResourceLoader,则此替代方案可能有意义。或者,如果您无法向构造函数添加 [Named]
-Attribute(例如因为它是第三方库...)。
另一种选择是提供 Ninject 更多关于如何构造类型的信息。例如:
Bind<Banner>().ToSelf()
.WithConstructorArgument(
typeof(IResourceLoader),
ctx => ctx.Kernel.Get<XmlLoader>());