More Effective C# Item3 : 运行时检查泛型参数的类型并提供特定的算法
我感觉这一条目应该算是对Item2的补充,还是在“约束”的条件下,如何使得程序得到最优化的结果,颇有“带着脚铐跳芭蕾”的意味。Item2中的条目可以看做是在有约束的情况下,对泛型类外部的影响;本条目可以看做是对泛型内部的影响。
通常情况下,.NET框架,或者我们自身针对不同项目制定的框架,都会包含一系列的接口或者基类,接口或者基类之间,会有继承的关系,形成一个系统的骨架,在此基础上根据具体的业务,对框架进行填充,使得最终的系统才会有血有肉。
在设计泛型类时,如果指定的“约束”是很宽泛的“约束”,即从类型层次结构上来看,“约束”指定的类型包含了子类型。那么可以在编写泛型方法时,对泛型参数的类型进行判断,如果该参数的类型属于某一种特定的类型(这里的特定类型一定会是泛型类型的子类型),那么就可以调用特定类型的方法,从而可以充分利用子类型的特点。
我们还是使用《More Effective C#》中提供的示例进行说明吧,来看下面的代码。
代码
上述代码实现了一个对列表进行反转的功能,它指定的“约束”是比较宽泛的,在代码中,并没有对泛型参数的类型再做进一步的判断和处理。
1 public sealed class ReserseEnumerable<T> : IEnumerable<T>
2 {
3 private class ReserseEnumerator : IEnumerator<T>
4 {
5 int currentIndex;
6 IList<T> collection;
7 public ReserseEnumerator(IList<T> srcCollection)
8 {
9 collection = srcCollection;
10 currentIndex = collection.Count;
11 }
12
13 #region IEnumerator<T> Members
14
15 public T Current
16 {
17 get { return collection[currentIndex]; }
18 }
19
20 #endregion
21
22 #region IDisposable Members
23
24 public void Dispose()
25 {
26
27 }
28
29 #endregion
30
31 #region IEnumerator Members
32
33 object IEnumerator.Current
34 {
35 get { return this.Current; }
36 }
37
38 public bool MoveNext()
39 {
40 return --currentIndex >= 0;
41 }
42
43 public void Reset()
44 {
45 currentIndex = collection.Count;
46 }
47
48 #endregion
49 }
50
51 IEnumerable<T> sourceSequence;
52 public IList<T> originalSequence;
53
54 public ReserseEnumerable(IEnumerable<T> sequence)
55 {
56 sourceSequence = sequence;
57 }
58 #region IEnumerable<T> Members
59
60 public IEnumerator<T> GetEnumerator()
61 {
62 if (originalSequence == null)
63 {
64 originalSequence = new List<T>();
65 foreach (T item in sourceSequence)
66 {
67 originalSequence.Add(item);
68 }
69 }
70 return new ReserseEnumerator(originalSequence);
71 }
72
73 #endregion
74
75 #region IEnumerable Members
76
77 IEnumerator System.Collections.IEnumerable.GetEnumerator()
78 {
79 return this.GetEnumerator();
80 }
81
82 #endregion
83 }
这里有必要说明一点,上面的代码是没有错误的,对于使用者来说,它从最大程度上开放了“约束”。但是在内部实现方面,我们还可以做以下优化,来看一下IReserseEnumerable<T>的构造函数,我们可以对其进行以下改动。
代码
对于GetEnumerator<T>方法来说,我们可以对其进行以下改动。
1 public ReverseEnumerable(IEnumerable<T> sequence)
2 {
3 sourceSequence = sequence;
4 // If sequence doesn't implement IList<T>,
5 // originalSequence is null, so this works
6 // fine.
7 originalSequence = sequence as IList<T>;
8 }
9
10 public ReverseEnumerable(IList<T> sequence)
11 {
12 sourceSequence = sequence;
13 originalSequence = sequence;
14 }
代码
1 public IEnumerator<T> GetEnumerator()
2 {
3 // Create a copy of the original sequence,
4 // so it can be reversed.
5 if (originalSequence == null)
6 {
7 if (sourceSequence is ICollection<T>)
8 {
9 ICollection<T> source = sourceSequence
10 as ICollection<T>;
11 originalSequence = new List<T>(source.Count);
12 }
13 else
14 originalSequence = new List<T>();
15 foreach (T item in sourceSequence)
16 originalSequence.Add(item);
17 }
18 return new ReverseEnumerator(originalSequence);
19 }
总结:我们可以在泛型约束的范围内,通过对泛型参数的类型进行判断和处理,这样在照顾到重用性的同时,也可以尽可能的提高程序的性能。
作者:李潘
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。