摘要

在前面的章节中,我们看了在单一的绑定条件下Ninject能够处理依赖类型,就是说,每个服务类型只绑定到单一的实现类型。然而,有些情况下我们需要绑定一个抽象服务类型到多个实现,这叫多个绑定。多个绑定有两种情况。第一个是插件模型实现,另一个是上下文绑定。这篇文章介绍插件模型实现,下一篇文章介绍上下文绑定。

附:程序下载

插件模型让一个应用程序获得很强的可扩展性而不用修改源代码。下面的例子,我们将实现一个音乐播放器应用程序,使用解码插件来支持不同的音乐格式。这个应用程序使用两个内置的解码器,也可以添加更多的解码器来扩展我们播放器支持的格式。请注意为了让应用程序尽可能简单,许多复杂的细节将不被实现。

先定义一个解码器接口:

     public interface ICodec
{
string Name { get; }
bool CanDecode(string extension);
Stream Decode(Stream inStream);
}

添加两个解码器类实现解码器接口:

Mp3:

     public class Mp3Codec : ICodec
{
public string Name
{
get
{
return "MP3 Audio";
}
} public bool CanDecode(string extension)
{
return extension == ".mp3";
} public Stream Decode(Stream inStream)
{
//some decode logic added here
return null;
}
}

Wma:

 public class WmaCodec : ICodec
{
public string Name
{
get
{
return "Windows Media Auido";
}
} public bool CanDecode(string extension)
{
return extension == ".wma";
} public Stream Decode(Stream inStream)
{
//some decode logic added here
return null;
}
}

下一步是实现我们可插拔的播放器类。让播放器可扩展的是他依赖一系列的ICodec对象,而不是某些具体的解码器:

 public class Player
{
private readonly ICodec[] codecs;
// Note that the constructor parameter is not a single ICodec.
public Player(IEnumerable<ICodec> codecs)
{
this.codecs = codecs.ToArray();
}
}

然后添加一个Play方法到播放器类:

 public void Play(FileInfo fileInfo)
{
ICodec supportingCodec = FindCodec(fileInfo.Extension);
using (var rawStream = fileInfo.OpenRead())
{
var decodedStream = supportingCodec.Decode(rawStream);
PlayStream(decodedStream);
}
}

这个方法接收一个FileInfo对象,查找合适的解码器后,解码播放这个文件。

实现FindCodec方法:

 private ICodec FindCodec(string extension)
{
foreach (ICodec codec in codecs)
if (codec.CanDecode(extension))
return codec;
throw new Exception("File type not supported.");
}

FindCodec调用每个codec对象的CanDecode方法来找到支持这个文件扩展名的解码器。如果找不到任何合适的解码器,将抛出一个异常。我们需要记住的一件事是没有具体的解码器在foreach循环之前被解析。

最后在Main方法里添加下面的代码:

 using (var kernel = new StandardKernel())
{
kernel.Bind(b => b.FromAssembliesMatching("*")
.SelectAllClasses()
.InheritedFrom<ICodec>()
.BindAllInterfaces());
}

前面的约定指示Ninject自动注册所有的ICodec接口的实现而不是为他们分别每个都声明绑定。

因为ICodec类型被绑定到多个实现,他只能被解析成一系列的对象而不是单一的对象。因此,使用下面的构造函数解析ICodec将导致一个运行时异常:

 public Consumer(ICodec codec){}

下面的代码也将产生运行时异常:

 ICodec codec = Kernel.Get<ICodec>();

上面两行代码,Ninject将试着解析ICodec接口,但是它发现多于一个的具体的实现类型。代替使用Get<T>,我们可以调用GetAll<T>方法来得到ICodec的所有实现。下面的代码显示所有的支持的codec:

 IEnumerable<ICodec> codecs = kernel.GetAll<ICodec>();
foreach (ICodec codec in codecs)
System.Console.WriteLine(codec.Name);

现在,任何的在应用程序的根路径下,有ICodec实现的程序集都将被我们的播放器应用程序认为是一个codec插件。我们的应用程序甚至不需要添加对codec工程的引用。

下面是完整的播放器类代码:

     public class Player
{
private readonly ICodec[] _codecs; // Note that the constructor parameter is not a single ICodec.
public Player(IEnumerable<ICodec> codecs)
{
this._codecs = codecs.ToArray();
} public void Play(FileInfo fileInfo)
{
ICodec supportingCodec = FindCodec(fileInfo.Extension);
using (var rawStream = fileInfo.OpenRead())
{
var decodedStream = supportingCodec.Decode(rawStream);
PlayStream(decodedStream);
}
} private void PlayStream(Stream decodedStream)
{
return;
} private ICodec FindCodec(string extension)
{
foreach (ICodec codec in _codecs)
{
if (codec.CanDecode(extension))
{
return codec;
}
}
throw new Exception("File type not supported.");
}
}

Ninject之旅之八:Ninject插件模型(附程序下载)的更多相关文章

  1. Ninject之旅之九:Ninject上下文绑定(附程序下载)

    摘要 既然在插件模型里,每一个服务类型可以被映射到多个实现,绑定方法不用决定要返回哪个实现.因为kernel应该返回所有的实现.然而,上下文绑定是多个绑定场景,在这个场景里,kernel需要根据给定的 ...

  2. Ninject之旅之二:开始使用Ninject(附程序下载)

    摘要 这篇文章介绍怎样将Ninject添加到实际的项目中,使用Ninject框架最基本的功能.首先用一个Hello World例子介绍怎么添加和使用Ninject.然后用一个更复杂的例子,介绍Ninj ...

  3. Ninject之旅之十二:Ninject在Windows Form程序上的应用(附程序下载)

    摘要: 下面的几篇文章介绍如何使用Ninject创建不同类型的应用系统.包括: Windows Form应用系统 ASP.NET MVC应用系统 ASP.NET Web Form应用系统 尽管对于不同 ...

  4. Ninject之旅之十三:Ninject在ASP.NET MVC程序上的应用(附程序下载)

    摘要: 在Windows客户端程序(WPF和Windows Forms)中使用Ninject和在控制台应用程序中使用Ninject没什么不同.在这些应用程序里我们不需要某些配置用来安装Ninject, ...

  5. Ninject之旅之十四:Ninject在ASP.NET Web Form程序上的应用(附程序下载)

    摘要 ASP.NET Web Forms没有像MVC那样的可扩展性,也不可能使它创建UI页面支持没有构造函数的的激活方式.这个Web Forms应用程序的的局限性阻止了它使用构造函数注入模式,但是仍能 ...

  6. Ninject之旅之十一:Ninject动态工厂(附程序下载)

    摘要 如果我们已经知道了一个类所有的依赖项,在我们只需要依赖项的一个实例的场景中,在类的构造函数中引入一系列的依赖项是容易的.但是有些情况,我们需要在一个类里创建依赖项的多个实例,这时候Ninject ...

  7. NHibernate系列文章二十二:NHibernate查询之HQL查询(附程序下载)

    摘要 NHibernate提供了多种查询方式,最早的HQL语言查询.Criteria查询和SQL Query,到NHibernate 3.0的Linq NHibernate,NHIbernate 4. ...

  8. NHibernate系列文章二十八:NHibernate Mapping之Auto Mapping(附程序下载)

    摘要 上一篇文章介绍了Fluent NHibernate基础知识.但是,Fluent NHibernate提供了一种更方便的Mapping方法称为Auto Mapping.只需在代码中定义一些Conv ...

  9. NHibernate系列文章二十七:NHibernate Mapping之Fluent Mapping基础(附程序下载)

    摘要 从这一节起,介绍NHibernate Mapping的内容.前面文章都是使用的NHibernate XML Mapping.NHibernate XML Mapping是NHibernate最早 ...

随机推荐

  1. [原创]cocos2d-x研习录-第三阶 特性之物理引擎

    游戏物理引擎是指在游戏中涉及物理现象的逻辑处理,它用于模拟现实世界的各种物理规律(如赛车碰撞.子弹飞行.物体掉落等),让玩家能够在游戏中有真实的体验. Cocos2D-x中支持Box2D和Chipmu ...

  2. 查看旧版jexus命令

    查看jexus版本 curl http://localhost/info

  3. DTO对象

    在EF中,EF生成的对象都是代理对象,这些对象看上去是实体类对象,但是其实都是EF封装好的代理类对象.所以调用EF查询得到的代理类对象有继承于实体对象,所以可以用实体类对象来接收返回的代理类对象.EF ...

  4. android模拟器没法通过localhost访问本地服务器的解决

    当android项目访问在一台服务器上的WEB服务时,没法通过localhost或者127.0.0.1来访问.模拟器把它自己作为了localhost,代码中使用localhost或者127.0.0.1 ...

  5. MySQL 使用笔记

    1. How to export the database of mysql go to command line,  use "CMD" cd C:\Program Files\ ...

  6. mysql:权限分配

    grant all privileges on *.* to  name@localhost identified by '1'; flush privileges;

  7. BizTalk调用WS-Security的web services

    最近做个项目,biztalk跟OTM(Oracle Transportation Management)系统做对接,双方通过web services通讯,这部分是BizTalk调用OTM的web se ...

  8. E: Unable to correct problems, you have held broken packages 解决方法

    在Ubuntu中安装软件的时候经常碰到E: Unable to correct problems, you have held broken packages.的错误,顾名思义是因为某些软件包冲突导致 ...

  9. collectionview使用

    创建UICollectionViewFlowLayout 对象来设置相关的布局,包括itemSize,headerReferenceSize,sectionInset.设置对应的布局大小,相关的和顶部 ...

  10. 关于print和echo的区别

    我的想法是print是函数,echo是语句.有一个点很难去说明就是为什么可以执行print 666.可以这样不加括号,象print(666);至于为什么一定要认为print是函数,而非网上说的语句和函 ...