标签:属性 另一个 例子 它的 忘记 www readonly 上下文 const
摘要
在前面的章节中,我们看了在单一的绑定条件下Ninject能够处理依赖类型,就是说,每个服务类型只绑定到单一的实现类型。然而,有些情况下我们需要绑定一个抽象服务类型到多个实现,这叫多个绑定。多个绑定有两种情况。第一个是插件模型实现,另一个是上下文绑定。这篇文章介绍插件模型实现,下一篇文章介绍上下文绑定。
插件模型让一个应用程序获得很强的可扩展性而不用修改源代码。下面的例子,我们将实现一个音乐播放器应用程序,使用解码插件来支持不同的音乐格式。这个应用程序使用两个内置的解码器,也可以添加更多的解码器来扩展我们播放器支持的格式。请注意为了让应用程序尽可能简单,许多复杂的细节将不被实现。
先定义一个解码器接口:
1 public interface ICodec
2 {
3 string Name { get; }
4 bool CanDecode(string extension);
5 Stream Decode(Stream inStream);
6 }
添加两个解码器类实现解码器接口:
Mp3:
1 public class Mp3Codec : ICodec
2 {
3 public string Name
4 {
5 get
6 {
7 return "MP3 Audio";
8 }
9 }
10
11 public bool CanDecode(string extension)
12 {
13 return extension == ".mp3";
14 }
15
16 public Stream Decode(Stream inStream)
17 {
18 //some decode logic added here
19 return null;
20 }
21 }
Wma:
1 public class WmaCodec : ICodec
2 {
3 public string Name
4 {
5 get
6 {
7 return "Windows Media Auido";
8 }
9 }
10
11 public bool CanDecode(string extension)
12 {
13 return extension == ".wma";
14 }
15
16 public Stream Decode(Stream inStream)
17 {
18 //some decode logic added here
19 return null;
20 }
21 }
下一步是实现我们可插拔的播放器类。让播放器可扩展的是他依赖一系列的ICodec对象,而不是某些具体的解码器:
1 public class Player
2 {
3 private readonly ICodec[] codecs;
4 // Note that the constructor parameter is not a single ICodec.
5 public Player(IEnumerable<ICodec> codecs)
6 {
7 this.codecs = codecs.ToArray();
8 }
9 }
然后添加一个Play方法到播放器类:
1 public void Play(FileInfo fileInfo)
2 {
3 ICodec supportingCodec = FindCodec(fileInfo.Extension);
4 using (var rawStream = fileInfo.OpenRead())
5 {
6 var decodedStream = supportingCodec.Decode(rawStream);
7 PlayStream(decodedStream);
8 }
9 }
这个方法接收一个FileInfo对象,查找合适的解码器后,解码播放这个文件。
实现FindCodec方法:
1 private ICodec FindCodec(string extension)
2 {
3 foreach (ICodec codec in codecs)
4 if (codec.CanDecode(extension))
5 return codec;
6 throw new Exception("File type not supported.");
7 }
FindCodec调用每个codec对象的CanDecode方法来找到支持这个文件扩展名的解码器。如果找不到任何合适的解码器,将抛出一个异常。我们需要记住的一件事是没有具体的解码器在foreach循环之前被解析。
最后在Main方法里添加下面的代码:
1 using (var kernel = new StandardKernel())
2 {
3 kernel.Bind(b => b.FromAssembliesMatching("*")
4 .SelectAllClasses()
5 .InheritedFrom<ICodec>()
6 .BindAllInterfaces());
7 }
前面的约定指示Ninject自动注册所有的ICodec接口的实现而不是为他们分别每个都声明绑定。
因为ICodec类型被绑定到多个实现,他只能被解析成一系列的对象而不是单一的对象。因此,使用下面的构造函数解析ICodec将导致一个运行时异常:
1 public Consumer(ICodec codec){}
下面的代码也将产生运行时异常:
1 ICodec codec = Kernel.Get<ICodec>();
上面两行代码,Ninject将试着解析ICodec接口,但是它发现多余一个具体的实现类型。代替使用Get<T>,我们可以调用GetAll<T>方法来得到ICodec的所有实现。下面的代码显示所有的支持的codec:
1 IEnumerable<ICodec> codecs = kernel.GetAll<ICodec>(); 2 foreach (ICodec codec in codecs) 3 System.Console.WriteLine(codec.Name);
现在,任何的在应用程序的根路径下,有ICodec实现的程序集都将被我们的播放器应用程序认为是一个codec插件。我们的应用程序甚至不需要添加对codec工程的引用。
下面是完整的播放器类代码:
1 public class Player
2 {
3 private readonly ICodec[] _codecs;
4
5 // Note that the constructor parameter is not a single ICodec.
6 public Player(IEnumerable<ICodec> codecs)
7 {
8 this._codecs = codecs.ToArray();
9 }
10
11 public void Play(FileInfo fileInfo)
12 {
13 ICodec supportingCodec = FindCodec(fileInfo.Extension);
14 using (var rawStream = fileInfo.OpenRead())
15 {
16 var decodedStream = supportingCodec.Decode(rawStream);
17 PlayStream(decodedStream);
18 }
19 }
20
21 private void PlayStream(Stream decodedStream)
22 {
23 return;
24 }
25
26 private ICodec FindCodec(string extension)
27 {
28 foreach (ICodec codec in _codecs)
29 {
30 if (codec.CanDecode(extension))
31 {
32 return codec;
33 }
34 }
35 throw new Exception("File type not supported.");
36 }
37 }
标签:属性 另一个 例子 它的 忘记 www readonly 上下文 const
原文地址:http://www.cnblogs.com/Leo_wl/p/6078420.html