摘要

在前面的章节中,我们看了在单一的绑定条件下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.");
}
}

最新文章

  1. PHP之Memcache缓存详解
  2. 微信小程序-视图事件
  3. JavaScript eval() 函数
  4. Android的init过程(二):初始化语言(init.rc)解析
  5. MATLAB学习笔记(二)&mdash;&mdash;主要是MATLAB的矩阵知识
  6. (C# 基础) Datatable
  7. python的http请求应用--每日签到
  8. hdu4427Math Magic
  9. Web电子商务网(三层)V2.0源码
  10. 文成小盆友python-num4 装饰器,内置函数
  11. @synthesize 与@dynamic区别
  12. Common Lisp学习笔记(0):从SLIME开始 | 优哉·幽斋
  13. 学习笔记 broswerify + watchify + beefy
  14. Firefox firebug and xpath checker
  15. Java关于使用“final”修饰基本类型的注意事项
  16. 报表打印错误:Forcing NLS_NUMERIC_CHARACTERS to: &#39;.,&#39; for XDO processing
  17. node.js http接口调试时请求串行特性分析
  18. 虚拟机安装ssh,关闭防火墙
  19. ESP32作为接入点AP
  20. 图片 100%显示. img 全部显示.

热门文章

  1. 【转载】Python 描述符简介
  2. OPENVPN
  3. #uwp# XMAL
  4. [PHP] - Apache + PHP 环境搭建
  5. 将 ASP.NET MVC3 Razor 项目部署到虚拟主机中
  6. ajax-服务器响应
  7. c语言中static的用法,包括全局变量和局部变量用static修饰
  8. Python 网络编程(二)
  9. OAF_开发系列04_实现OAF查询4种不同的实现方式的比较和实现(案例)
  10. shared_ptr 线程安全