C# Ninject工厂扩建

C# Ninject工厂扩建,c#,dependency-injection,ninject,ninject.web.mvc,ninject-extensions,C#,Dependency Injection,Ninject,Ninject.web.mvc,Ninject Extensions,我在绕着Ninject工厂分机转的时候有点麻烦 我的班级结构如下 public class Resource { public IResourceLoader ResourceLoader {get;set;} public Resource(IResourceLoader ResourceLoader) { this.ResourceLoader = ResourceLoader ; } } publi

我在绕着Ninject工厂分机转的时候有点麻烦

我的班级结构如下

 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"; }
 }
我正在尝试基于命名属性show实现基于约定的过滤。因此,我实现了以下接口

 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());
谢谢

让我试着回答你的问题,我不是100%确定我正确理解了你的问题,所以如果我没有理解,请给我反馈

现在,您的基本问题是希望注入
IResourceLoader
——但根据注入内容的不同,它应该是
XMLLoader
PNGLoader

您已经正确地将命名绑定标识为选择适当的
IResourceLoader
的一种可能解决方案

但是,您不需要将
NamedLikeFactory
[Named]
-属性模式结合起来来实现所需的功能,其中一个就足够了,在这里,
[Named]
-属性可能是这两个模式中更好的选择(还有第三个我将在后面讨论)

下面是你要做的:

public const string XmlLoaderName = "XmlLoader";
public const string PngLoaderName = "PngLoader";

Bind<IResourceLoader>().To<XMLLoader>()
    .Named(XmlLoaderName);
Bind<IResourceLoader>().To<PNGLoader>()
    .Named(PngLoaderName);
基本上就是这样

现在要在控制器中使用它,您需要做的就是:

public class HomeController
{
    public HomeController(Banner baner, MetaData metaData)
    {
    ...
    }
}
不需要使用工厂。除了,如果您需要为每个请求实例化一个
横幅
元数据
实例,在这种情况下,您将创建一个工厂接口:

public interface IResourceFactory
{
    Banner CreateBanner();

    MetaData CreateMetaData();
}
这就像:

Bind<IResourceFactory>().ToFactory(); 
// ToFactory is an extension method from Ninject.Extensions.Factory

命名的
绑定的替代方法:也可以使用条件绑定,如:

Bind<IResourceLoader>().To<XMLLoader>()
   .WhenInjectedInto<Banner>();
如果注入了ResourceLoader的类非常有限,那么这种替代方法是有意义的。或者,如果无法向ctor添加
[Named]
-属性(例如,因为它是第三方库…)

另一种选择是为Ninject提供更多关于如何构造类型的信息。例如:

Bind<Banner>().ToSelf()
    .WithConstructorArgument(
        typeof(IResourceLoader),
        ctx => ctx.Kernel.Get<XmlLoader>());
Bind().ToSelf()
.带构造函数参数(
类型(IResourceLoader),
ctx=>ctx.Kernel.Get());

这就像一个符咒!我以前尝试过第一个解决方案,但由于某些原因,它不起作用。我更喜欢上一个自绑定和注入构造函数参数的解决方案,看起来更简洁。谢谢你,先生!
public class HomeController
{
    private readonly IResourceFactory resourceFactory;

    public HomeController(IResourceFactory resourceFactory)
    {
        this.resourceFactory = resourceFactory;
    }

    public ActionResult Index()
    {
        var banner = this.resourceFactory.CreateBanner();
        ....
    }
}
Bind<IResourceLoader>().To<XMLLoader>()
   .WhenInjectedInto<Banner>();
public Banner(IResourceLoader resourceLoader)
{
...
}
Bind<Banner>().ToSelf()
    .WithConstructorArgument(
        typeof(IResourceLoader),
        ctx => ctx.Kernel.Get<XmlLoader>());