首页 文章

Ninject Factory Extension

提问于
浏览
1

我在Ninject Factory Extension周围缠绕我有点麻烦 .

我有以下类结构

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属性实现基于约定的过滤,如show 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根据它将它传递给基础构造函数的构造函数中的[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? */);

        ...
    }
}

谢谢

1 回答

  • 2

    让我试着回答你的问题,我正确理解你的问题,所以如果我没有,请给我反馈 .

    现在,你的基本问题是你要注入 IResourceLoader - 但是根据你注入的内容,它应该是 XMLLoaderPNGLoader .

    您已正确识别命名绑定作为选择适当的 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);
    

    然后在ctor中指定适当的类型(就像你一样):

    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)
        {
        ...
        }
    }
    

    无需使用工厂 . 除非您需要为每个请求实例化一个 BannerMetaData 实例,在这种情况下您将创建一个工厂接口:

    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)
    {
    ...
    }
    

    如果's a very limited set of classes which get a ResourceLoader injected. Or if you can' t将 [Named] -Attribute添加到ctor(例如因为它是第三方库...),则此替代方法可能有意义 .

    另一个替代方案是给Ninject更多关于如何构造类型的信息 . 例如:

    Bind<Banner>().ToSelf()
        .WithConstructorArgument(
            typeof(IResourceLoader),
            ctx => ctx.Kernel.Get<XmlLoader>());
    

相关问题