c#2.0新特性
范型
我们知道通用的数据结构可以采用object存储任何数据类型。使用object问题是:
- 显示的强制转带来的代码复杂性
- 换装箱拆箱的性能损失(为什么有性能损失?因为涉及动态内存分配和运行时类型检查)。还有一些运行时才会出现的类型转换异常也是我们难以在代码编写的时候能够检查到的,防不胜防。
范型应时而生,它的思路是什么呢?它接受带有类型参数并存储这个类型而不转换它,类型参数在类名字后的<T>中指定。T相当于一个占位符,直到使用的时候才指定一个实际的类型。确切的说当应用程序首次创建一个构造范型类型的实例时,.net公共语言运行时的实时编译器JIT将在进程中把范型IL和元数据转化为本地代码并把类型参数转化为实际的类型。对于这个泛型类型的后续引用将会使用相同的本机代码。这也就是传说中的范型类型实例化。
看一段代码:
范型的一个有趣话题:约束
问题溯源:由于T代表的可能是任何类型,所以我们使用T的方法仅限于Equals GetHasCode ToString,那么我们要使用某些特定数据类型的方法呢?比如实现了IComparable接口的数据类型的CompareTo方法?

一种方法是强制转换到IComparable接口。这种方法的缺点是:1.进行运行时动态类型检查增加了性能上的开销,2.自然地如果key没有实现IComparable接口的异常报告推迟到了运行时
另一种方法就是约束列表,关键词是where,后面跟的是类或者接口的列表,还有一个可选、特殊的new()约束;其实就是说这个类型必须要有一个公开无参构造函数,这就允许泛型类使用这种构造函数来创建实例。约束是一把双刃剑,一方面它提供了编译时类型检查,增强了性能,但是它也限制了范型类型的能力。

范型方法
范型方法在方法名字后面使用<>指定一个或者多个类型参数,类型参数可以出现在参数列表,返回类型和方法体内。编译器会使用一种类型推断的机制通过其他参数类推断正确的类型参数。
给出一些范型的例子:
Code
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->1
publicclassTest<T>
2

{
3
publicTitem
{get;set;}
4
5
publicvoidDisplay()
6

{
7
Console.WriteLine(item.ToString());
8
}
9
10
}
11
12
publicclassMap<K,V>
13

{
14
Dictionary<K,V>d=newDictionary<K,V>();
15
publicvoidAdd(Kkey,Vvalue)
16

{
17
18
d.Add(key,value);
19
}
20
publicvoidDisplay()
21

{
22
foreach(varitemind.Keys)
23

{
24
Console.WriteLine("Key:"+item+"Value:"+d[item]);
25
}
26
}
27
}
28
29
publicclassComparableTest<T>whereT:IComparable
30

{
31
publicTitem
{get;set;}
32
33
publicvoidDisplay()
34

{
35
if(item.CompareTo(10)>0)
36

{
37
Console.WriteLine(item.ToString()+">"+"10");
38
}
39
else
40

{
41
Console.WriteLine(item.ToString()+"<"+"10");
42
}
43
}
44
45
}
46
47
publicclassMapWithConstraint<K,V>whereV:new()
48

{
49
Dictionary<K,V>d=newDictionary<K,V>();
50
publicvoidAdd(Kkey,Vvalue)
51

{
52
53
d.Add(key,value);
54
}
55
publicvoidDisplay()
56

{
57
foreach(varitemind.Keys)
58

{
59
Console.WriteLine("Key:"+item+"Value:"+d[item]);
60
}
61
}
62
}
63
64
publicclassGenericMethodTest
65

{
66
publicTDisplay<T,V,K>(Tt,Kk,Vv)
67

{
68
Console.WriteLine(t.ToString()+""+k.ToString()+""+v.ToString());
69
returnt;
70
}
71
}
72
publicclassStudent
73

{
74
publicintID
{get;set;}
75
publicstringName
{get;set;}
76
}
77
classProgram
78

{
79
staticvoidMain(string[]args)
80

{
81
Test<int>t=newTest<int>();
82
t.item=10;
83
t.Display();
84
85
86
Map<string,int>map=newMap<string,int>();
87
map.Add("King",23);
88
map.Add("XiaoQiang",24);
89
map.Display();
90
91
ComparableTest<int>test=newComparableTest<int>();
92
test.item=123;
93
test.Display();
94
95
96
//ComparableTest<Student>test2=newComparableTest<Student>();
97
98
99
GenericMethodTestg=newGenericMethodTest();
100
Console.WriteLine(g.Display(23,32,52));
101
102
103
104
Console.ReadLine();
105
106
}
107
}
108
匿名方法
匿名方法其实就是体现了这样一个原则:如无必要,勿增实体;我们在一个简单的WinForm环境中来说明这个问题:一个按钮单击事件我们可以这样来定义响应代码。
1
this
.button1.Click
+=
delegate
2

{
3
this.label1.Text="King2002";
4
}
;
5

6
this
.button1.Click
+=
delegate
(
object
sender,System.EventArgsarg)
7

{
8
this.label1.Text="Test";
9
}
;
10
this
.button1.Click
+=
new
System.EventHandler(
this
.button1_Click);
11
private
void
button1_Click(
object
sender,EventArgse)
12

{
13
MessageBox.Show("Hello");
14
}
15

16

17
匿名方法使得代码对于委托的实现更加简单,匿名方法还有一个用途就是操作一些私有成员,因为它相当于共享了一部分代码。
这里会有一个疑问:匿名方法和委托类型的隐式转换有什么要求?答案:只要参数列表和委托类型的返回值是兼容的就可以完成转换。
- 参数列表兼容:无参数或者参数的数量、类型、修饰符严格匹配
- 无返回类型,所有return语句形管的表达式可以被隐式转换到委托的类型
后面我们会看到更简单使用delegate的例子。
迭代器
一个对象如果是可枚举的,那么我们可以使用foreach语句来遍历其中的元素。实际上是调用了这个对象的GetEnumberator方法,它返回一个enumberator(枚举器)。实现枚举器很难但是我们可以使用迭代器实现!
1
public
class
DaysOfTheWeek:System.Collections.IEnumerable
2

{
3
string[]m_Days=
{"Sun","Mon","Tue","Wed","Thr","Fri","Sat"};
4
5
publicSystem.Collections.IEnumeratorGetEnumerator()
6

{
7
for(inti=0;i<m_Days.Length;i++)
8

{
9
yieldreturnm_Days[i];
10
}
11
}
12
/Images/
分享到:
评论