假如这个世界上只剩下你一个人,当你正坐在屋子里的时候,这时突然响起了敲门声...
C#新特性:匿名类和扩展方法
上一篇 / 下一篇 2008-06-12 12:01:32 / 个人分类:微软技术
查看( 268 ) /
评论( 1 )
本文为原创,如需转载,请注明作者和出处,谢谢!
A/^UYf0ITPUB个人空间k*[ g*T{/s
一、用var定义变量ITPUB个人空间`/z1\HVJ
ITPUB个人空间"r'l$J6H?'b_d6Cx
在C#3.0中提供了一种新的声明变量的方式,这就是var。通过这个关键字,在声明变量时就无需指定类型了,变量类型是在初始化时由编译器确定的。代码如下:ITPUB个人空间)w;R$e Ih)r{0j
J1VcDT'ka5u3{0var ss = "abcd";ITPUB个人空间7E}(Cj)]3oof8eV
MessageBox.Show(ss.GetType().ToString());
8U6zy1QXe;B0
b)BI*m.Q"P0上面的代码将显示System.String,从而证明C#编译器已经将ss编译成了String变量了。而在输出ss后,再输入“.”后,会看到将String类型变量的相应方法和属性也列出来了,因此可以断定,C#将ss看成了String类型,而不是Object。所以使用var定义变量同时可以拥有Object和强类型的优点。
fu"|s PWy~0 不过大家不要将var看成是javascript的var,它们的区别是,javascript是弱类型的语言,而且javascript中的变量(也包括用var声明的变量)可以变换类型,如下面的javascript所示:
p bWnB{0ITPUB个人空间:Uhf6G[Bk
var s = "abcd";
.o TN\6KJTK0s=3;
[5Z0N1pz$UO)P0alert(s);ITPUB个人空间O|mq k&b5I$G
ITPUB个人空间 e+CS$N/]Yb
上面的代码第一次给s赋了一个字符串,而第二行代码又给赋了一个整数。这样的代码在javascript中没有任何问题。但在C#3.0中,var变量一但被初始化,确定类型后,就无法改变类型了。如下面的代码是无法编译通过的:ITPUB个人空间$L+E3vX1w(o"|g
ITPUB个人空间\r2VwMTW3^
var ss = "abcd";ITPUB个人空间0nH2c3\+LA@
ss = 44;
5CM;N5lXBR0ITPUB个人空间 D;K@o \5RRq
综上所述,在使用var定义变量时有以下四个特点:
X%M3Pe]0q0
%v3}P0OKF g01. 必须在定义时初始化。也就是必须是var s = “abcd”形式,而不能是如下形式:ITPUB个人空间RHRGUV7?r
var s;ITPUB个人空间!W+oy;QK*x0T0kw*q:h b-A7U
s = “abcd”;
nfy%]x0ITPUB个人空间4p~5[5v2_)Q
2. 一但初始化完成,就不能再给变量赋与初始化值类型不同的值了。
i~5hbG:R.h5S&F0
Md9n^xvk*eN03. var要求是局部变量。
V\6SgF*_C M0ITPUB个人空间`;]wZ{c
4. 使用var定义变量和object不同,它在效率上和使用强类型方式定义变量完全一样。但笔者建议如果事先知道变量的类型,尽量使用强类型方式来声明变量。否则,就会造成由于大量使用var,而使得开发人员很难断定某个变量是什么类型。这样不利于程序的维护和升级。
x WNFfpol$~3t1Q0ITPUB个人空间6Y0X*@p ABNY
虽然var有利有弊,但笔者个人认为,如果将动态语言转换成C#语言,可以考虑使用var来定义变量。这是因为动态语言没有类型,而要将其转换成强类型的C#语言,就必须给变量指定个类型,但事先确定类型是很费劲的,不如将其指定成var,再由C#编译器去确定变量的具体类型。那么如果在转换的过程中,发现动态语言的变量改变了类型,该怎么办呢?这个可以使用第三部分要讲的“匿名类”来解决这个问题。ITPUB个人空间i0M%~Zxs
ITPUB个人空间/}GkO/?6?A&X
二、初始化
(eT[5e{"\p7V1_0 如果一个类有public字段,在建立类的对象实例时可以使用下面的代码来初始化这些字段;
BXLU`l&e0
Z Q iX s*v_+x0public class MyClassITPUB个人空间4Q"XWr)dAQ
{
.lFf \6_^9i E0 public String field1;
,_BB4T7F4M#X$li @XS0 public int field2;ITPUB个人空间%BuX ]*M6D#X
public bool field3;ITPUB个人空间e"I HFB G
}ITPUB个人空间I-^-|+q5`+p,} }
ITPUB个人空间:ux3\L&j.Nz u7U:B
MyClass my = new MyClass();ITPUB个人空间 [(\Ml d vIN8Z%H6i
my.field1 = “abcd”;ITPUB个人空间%A#AIJL^
my.field2 = 44;ITPUB个人空间~!M,m?6h4hM"k
my.field3 = true;
,t^$S/{{0
G d5C6nX9m!?0 在C#3.0中提供了一种更简便的方法来初始化这些public变量,代码如下:ITPUB个人空间 n ?2E(T!i$i
ITPUB个人空间%pNI[D$z.NlYL O
MyClass my = new MyClassITPUB个人空间xuq,U1_}4PQ
{ITPUB个人空间an-^5l \suZ!c
field1 = “abcd”,ITPUB个人空间3x'}0GTY;K
field2 = 44;ITPUB个人空间O$cPi)z;d[
field3 =true;
u+f"w$ny'x0};ITPUB个人空间W!^REf
ITPUB个人空间4a] qD8t
上面的代码的写法有些象带参数的构造方法,但这将不是调用了MyClass的构造方法(因为MyClass并没有带三个参数的构造方法),而只是C#编译器玩的一个魔术。实际上,上面的代码在编译后,仍然和使用传统的初始化字段的方法一样。只是在语法上看起来更简单(至少不用写那么多个my)。要注意的的,使用这种方法初始化,必须是public的字段(不能是protected、private或默认修饰符的字段)。
C)n2yG6?C]8nb$Om0 在C#3.0中还改进了对集合类的初始化方式(使其初始化的方式类似于数组)。但遗憾的是,这种初始化方式只支持用泛型的集合类,也就是说,只有实现了System.Collections.Generic.违规广告ection<T>的集合类才可以使用这种初始化方法。代码如下:ITPUB个人空间,F/sg@R[A8bL*JZ3[:U
,?Kg2i|'fFH0List<string> myList = new List<string> { "data1", "data2", "data3" };
t)_u+tV l0foreach (string data in myList)
.| ~?t0RTQZ0{
,hpz'vYOH2K0 textBox1.AppendText(data);ITPUB个人空间E}2j WK
}
M2{Z9r0k0w"h?wwx0ITPUB个人空间&Ca"Ac[ZquR
三、匿名类
+J'EY/qyv0ITPUB个人空间9V;Fg(B#[q9K&@o n2D
在C#3.0中提供了一种新的建立类的方法,代码如下:ITPUB个人空间{.?_a,{$]KLB P
var my = newITPUB个人空间FNa9H:t6E3H0_
{ITPUB个人空间BH\p$p R0^.f
field1 = "abcd",
Sz'@"q"x/O||P0 field2 = 12
+|6}2Ai2MC0K*f0};
|O pq.Q@0MessageBox.Show(my.field1);
w/}q Q;uTtk1YJ0
.Y.OX xx\L!y0 C#编译器会自动推断my是一个有两个public字段的类的对象实例。也就是说相当于下面的代码:
t M.|y@0
1H%{"o$M/f&\n0public class MyClassITPUB个人空间Mz~$t7NC |N
{
$]$T UI&qJ$\)dI0 public String field1;ITPUB个人空间#^ }l c{-Grt
public int field2;
ih7Kl1m z m#_*VG#e0}ITPUB个人空间 S'q,T7k_iui5Hx
%]-id#W^#c{0var my = new MyClass();
#X#i5AK1W_$p&`p0my.field1 = "abcd";
c|j3L1zo2U-P0my.field2 = 25;ITPUB个人空间C5PC'E0Z"H8f
MessageBox.Show(my.field1);ITPUB个人空间9j&Y/SKg"Aou)J
ITPUB个人空间e/ZC-U8n W1J
在第一部分讲到如果动态语言在给变量赋值的过程中改变了变量类型,如果将其转换为强类型语言。当然,一种方法是将变量声明成object类型,或是使用匿名类来解决这个问题。代码如下:ITPUB个人空间*Ccv*NPt
var myVar = new
`u.y+|]0{ITPUB个人空间U,BQYi[Q q[p
field_string = “abcd”
G#i?g9SN N8z0 field_int = 12;ITPUB个人空间.KOh#v)^(z1` Q9B
};ITPUB个人空间0tk1Ad|"Y5h
t V$bO#G'[0 然后根据当前这个变量所使用的类型来决定该使用哪个类字段。ITPUB个人空间'V,TJ$D.N3N!~R#j
FP9w$`*f0四、扩展方法ITPUB个人空间X-m~BNY \9o
(Q#y_ }t0 这个世界上总是存在着很多奇妙的东西。然而,在这部分所介绍的扩展方法就是其中之一。从字面上看可能读者很难猜透“扩展方法”是什么意思。然而,看了下面的例子,就会感觉到非常的奇妙。ITPUB个人空间v1|N?)w#gsE
ITPUB个人空间rWuU'U0Bb
namespace ExtMethodITPUB个人空间 J$~JWZI
{ITPUB个人空间x+A$`%D3F9K
public class Class1ITPUB个人空间#na)feu
{ITPUB个人空间U;A f SFu T
public String s = "bill";
4tG,B0U}O.a*X0 }
*__zO1_vW'_1s)w.]0 public class Class2 : Class1ITPUB个人空间,]6~0F4Z[z-pN+} q
{
t/U-k&yW+me0 }ITPUB个人空间x1G9ed]5iHPyA
public static class AnyClassName
U[;Hd7G\0 {ITPUB个人空间n8LB-@pfx(B
public static String getName(this Class1 class1)
+il%i-By U:|0 {ITPUB个人空间B{0Wn~.e(i}7R
return class1.s + class1.s; ITPUB个人空间r"gK Z2n,\
}ITPUB个人空间S(V.y+O8mK
}ITPUB个人空间rp F K~[*w
ITPUB个人空间x#M8u9T5}_A
public partial class Form1 : Form
)W v G;p^v0 {ITPUB个人空间cN#hrw5a2N
bS8w ^ UH%B(a6k#]r|0 private void button1_Click(object sender, EventArgs e)ITPUB个人空间Pdt*B3pC)sd{
{ITPUB个人空间+b(q/_LB%X%P
Class1 c = new Class1();ITPUB个人空间M2H0Ml(Q1A&gg
MessageBox.Show(c.getName()); ITPUB个人空间+^8N t]|&L:A
Class2 c = new Class2();
rrA!X{ D rD0 MessageBox.Show(c.getName());
,H*i V0gqe%vh0 }ITPUB个人空间 cO*~ig
}
9kBt!Mxf0}
(Xd1y3uW1uMo]0
{/b E.@N%J"X0 看到上面的代码,也许很多人会感到奇怪,在Class1和Class2中并没有getName方法,怎么在调用时出来个getName方法呢?实际上,这就是扩展方法的用法,从本质上说,扩展方法就是将静态方法(必须声明成static)插入到某个类和其子类中(也就是说,在这些类中可以使用在外部定义的静态方法)。那么要往哪个类中插入呢?这就要在定义静态方法时指定了。大家可以看看getName方法的第一个参数,使用了this关键字,这就表明这个方法是一个扩展方法,后面的类型就是要插入该方法的类,在本例中是Class1,也就是说在Class1及其子类中都可以使用getName方法。上面的调用代码也相当于下面的代码:
H6_I ffc0Class2 c = new Class2();ITPUB个人空间P7w5LL,T
MessageBox.Show(AnyClassName.getName(c));ITPUB个人空间\+_!|'B:eta
7s~X f5bL0p2Kr0 但使用c.getName可能会更好一些,而且也降低了对静态方法所在的类(AnyClassName)的依赖性。
a8Wby-XN f9mA0
IWSmBaS/b0 在使用扩展方法时应注意以下几点:
]Qe[5c-qGU0
LnC-hZ5R*i+@Ub@l01. 扩展方法所在的类名可以是任意合法的类名。ITPUB个人空间0n c { }j6@,F
9o5} N3X!nc0r'~02. 扩展方法所在的类必须和使用扩展方法的代码在同一个命名空间里,否则无法编译通过。
z*J.q x3KZ-[yKe0ITPUB个人空间S)m uX/r7O+gJ[%k
3. 在本例中,Class1和Class2只能声明成public,因为AnyClassName被声明为public。如果AnyClassName不加修饰符,Class1和Class2也可以不加修饰符,当然,也可以被声明为public。也就是说,Class1和Class2必须有比AnyClassName具有更强的访问性。如下面代码所示:ITPUB个人空间]h8seI"? x4R)m2o"n
class Class1
9zr IbL4Dy0 {
?Hv"L}'JT0 public String s = "bill";
?n#O0e8NE+m3~0 }ITPUB个人空间4]v%wz.R:H~z7iV
class Class2 : Class1ITPUB个人空间&}| }l4OGgD
{ITPUB个人空间'Ic|l ?}Y,E
}ITPUB个人空间+L*q^4q!G#Y*@
static class AnyClassName // 这时如果前面加public是无法编译通过的。
zc5~5HDt;bk0 {
w ZLYdaC0 public static String getName(this Class1 class1)ITPUB个人空间 @TK&Wz;\Qn
{
"w2z2t9gF#Rk@0 return class1.s + class1.s; ITPUB个人空间K&y[yuJ.D
}ITPUB个人空间@,k-Q0cNi1fr7xk%U
}ITPUB个人空间 uml A0fRJ+y
U9G _:B q r@04. 如果在Class1或Class2中已经有getName方法了,那么Class1或Class2中的getName优先级更高。也就是说,扩展方法是无法覆盖原类中的同名(参数名和类型也相同)的方法的。
qu-dm#[]0ITPUB个人空间}-W5]T [,o f
扩展方法尤其在很多类需要同样的方法,而这些类又无法继承其它类时特别有用。当然,在要对某个类进行扩展,但我们并没有源代码时,扩展方法也可以派上用场。
A/^UYf0ITPUB个人空间k*[ g*T{/s
一、用var定义变量ITPUB个人空间`/z1\HVJ
ITPUB个人空间"r'l$J6H?'b_d6Cx
在C#3.0中提供了一种新的声明变量的方式,这就是var。通过这个关键字,在声明变量时就无需指定类型了,变量类型是在初始化时由编译器确定的。代码如下:ITPUB个人空间)w;R$e Ih)r{0j
J1VcDT'ka5u3{0var ss = "abcd";ITPUB个人空间7E}(Cj)]3oof8eV
MessageBox.Show(ss.GetType().ToString());
8U6zy1QXe;B0
b)BI*m.Q"P0上面的代码将显示System.String,从而证明C#编译器已经将ss编译成了String变量了。而在输出ss后,再输入“.”后,会看到将String类型变量的相应方法和属性也列出来了,因此可以断定,C#将ss看成了String类型,而不是Object。所以使用var定义变量同时可以拥有Object和强类型的优点。
fu"|s PWy~0 不过大家不要将var看成是javascript的var,它们的区别是,javascript是弱类型的语言,而且javascript中的变量(也包括用var声明的变量)可以变换类型,如下面的javascript所示:
p bWnB{0ITPUB个人空间:Uhf6G[Bk
var s = "abcd";
.o TN\6KJTK0s=3;
[5Z0N1pz$UO)P0alert(s);ITPUB个人空间O|mq k&b5I$G
ITPUB个人空间 e+CS$N/]Yb
上面的代码第一次给s赋了一个字符串,而第二行代码又给赋了一个整数。这样的代码在javascript中没有任何问题。但在C#3.0中,var变量一但被初始化,确定类型后,就无法改变类型了。如下面的代码是无法编译通过的:ITPUB个人空间$L+E3vX1w(o"|g
ITPUB个人空间\r2VwMTW3^
var ss = "abcd";ITPUB个人空间0nH2c3\+LA@
ss = 44;
5CM;N5lXBR0ITPUB个人空间 D;K@o \5RRq
综上所述,在使用var定义变量时有以下四个特点:
X%M3Pe]0q0
%v3}P0OKF g01. 必须在定义时初始化。也就是必须是var s = “abcd”形式,而不能是如下形式:ITPUB个人空间RHRGUV7?r
var s;ITPUB个人空间!W+oy;QK*x0T0kw*q:h b-A7U
s = “abcd”;
nfy%]x0ITPUB个人空间4p~5[5v2_)Q
2. 一但初始化完成,就不能再给变量赋与初始化值类型不同的值了。
i~5hbG:R.h5S&F0
Md9n^xvk*eN03. var要求是局部变量。
V\6SgF*_C M0ITPUB个人空间`;]wZ{c
4. 使用var定义变量和object不同,它在效率上和使用强类型方式定义变量完全一样。但笔者建议如果事先知道变量的类型,尽量使用强类型方式来声明变量。否则,就会造成由于大量使用var,而使得开发人员很难断定某个变量是什么类型。这样不利于程序的维护和升级。
x WNFfpol$~3t1Q0ITPUB个人空间6Y0X*@p ABNY
虽然var有利有弊,但笔者个人认为,如果将动态语言转换成C#语言,可以考虑使用var来定义变量。这是因为动态语言没有类型,而要将其转换成强类型的C#语言,就必须给变量指定个类型,但事先确定类型是很费劲的,不如将其指定成var,再由C#编译器去确定变量的具体类型。那么如果在转换的过程中,发现动态语言的变量改变了类型,该怎么办呢?这个可以使用第三部分要讲的“匿名类”来解决这个问题。ITPUB个人空间i0M%~Zxs
ITPUB个人空间/}GkO/?6?A&X
二、初始化
(eT[5e{"\p7V1_0 如果一个类有public字段,在建立类的对象实例时可以使用下面的代码来初始化这些字段;
BXLU`l&e0
Z Q iX s*v_+x0public class MyClassITPUB个人空间4Q"XWr)dAQ
{
.lFf \6_^9i E0 public String field1;
,_BB4T7F4M#X$li @XS0 public int field2;ITPUB个人空间%BuX ]*M6D#X
public bool field3;ITPUB个人空间e"I HFB G
}ITPUB个人空间I-^-|+q5`+p,} }
ITPUB个人空间:ux3\L&j.Nz u7U:B
MyClass my = new MyClass();ITPUB个人空间 [(\Ml d vIN8Z%H6i
my.field1 = “abcd”;ITPUB个人空间%A#AIJL^
my.field2 = 44;ITPUB个人空间~!M,m?6h4hM"k
my.field3 = true;
,t^$S/{{0
G d5C6nX9m!?0 在C#3.0中提供了一种更简便的方法来初始化这些public变量,代码如下:ITPUB个人空间 n ?2E(T!i$i
ITPUB个人空间%pNI[D$z.NlYL O
MyClass my = new MyClassITPUB个人空间xuq,U1_}4PQ
{ITPUB个人空间an-^5l \suZ!c
field1 = “abcd”,ITPUB个人空间3x'}0GTY;K
field2 = 44;ITPUB个人空间O$cPi)z;d[
field3 =true;
u+f"w$ny'x0};ITPUB个人空间W!^REf
ITPUB个人空间4a] qD8t
上面的代码的写法有些象带参数的构造方法,但这将不是调用了MyClass的构造方法(因为MyClass并没有带三个参数的构造方法),而只是C#编译器玩的一个魔术。实际上,上面的代码在编译后,仍然和使用传统的初始化字段的方法一样。只是在语法上看起来更简单(至少不用写那么多个my)。要注意的的,使用这种方法初始化,必须是public的字段(不能是protected、private或默认修饰符的字段)。
C)n2yG6?C]8nb$Om0 在C#3.0中还改进了对集合类的初始化方式(使其初始化的方式类似于数组)。但遗憾的是,这种初始化方式只支持用泛型的集合类,也就是说,只有实现了System.Collections.Generic.违规广告ection<T>的集合类才可以使用这种初始化方法。代码如下:ITPUB个人空间,F/sg@R[A8bL*JZ3[:U
,?Kg2i|'fFH0List<string> myList = new List<string> { "data1", "data2", "data3" };
t)_u+tV l0foreach (string data in myList)
.| ~?t0RTQZ0{
,hpz'vYOH2K0 textBox1.AppendText(data);ITPUB个人空间E}2j WK
}
M2{Z9r0k0w"h?wwx0ITPUB个人空间&Ca"Ac[ZquR
三、匿名类
+J'EY/qyv0ITPUB个人空间9V;Fg(B#[q9K&@o n2D
在C#3.0中提供了一种新的建立类的方法,代码如下:ITPUB个人空间{.?_a,{$]KLB P
var my = newITPUB个人空间FNa9H:t6E3H0_
{ITPUB个人空间BH\p$p R0^.f
field1 = "abcd",
Sz'@"q"x/O||P0 field2 = 12
+|6}2Ai2MC0K*f0};
|O pq.Q@0MessageBox.Show(my.field1);
w/}q Q;uTtk1YJ0
.Y.OX xx\L!y0 C#编译器会自动推断my是一个有两个public字段的类的对象实例。也就是说相当于下面的代码:
t M.|y@0
1H%{"o$M/f&\n0public class MyClassITPUB个人空间Mz~$t7NC |N
{
$]$T UI&qJ$\)dI0 public String field1;ITPUB个人空间#^ }l c{-Grt
public int field2;
ih7Kl1m z m#_*VG#e0}ITPUB个人空间 S'q,T7k_iui5Hx
%]-id#W^#c{0var my = new MyClass();
#X#i5AK1W_$p&`p0my.field1 = "abcd";
c|j3L1zo2U-P0my.field2 = 25;ITPUB个人空间C5PC'E0Z"H8f
MessageBox.Show(my.field1);ITPUB个人空间9j&Y/SKg"Aou)J
ITPUB个人空间e/ZC-U8n W1J
在第一部分讲到如果动态语言在给变量赋值的过程中改变了变量类型,如果将其转换为强类型语言。当然,一种方法是将变量声明成object类型,或是使用匿名类来解决这个问题。代码如下:ITPUB个人空间*Ccv*NPt
var myVar = new
`u.y+|]0{ITPUB个人空间U,BQYi[Q q[p
field_string = “abcd”
G#i?g9SN N8z0 field_int = 12;ITPUB个人空间.KOh#v)^(z1` Q9B
};ITPUB个人空间0tk1Ad|"Y5h
t V$bO#G'[0 然后根据当前这个变量所使用的类型来决定该使用哪个类字段。ITPUB个人空间'V,TJ$D.N3N!~R#j
FP9w$`*f0四、扩展方法ITPUB个人空间X-m~BNY \9o
(Q#y_ }t0 这个世界上总是存在着很多奇妙的东西。然而,在这部分所介绍的扩展方法就是其中之一。从字面上看可能读者很难猜透“扩展方法”是什么意思。然而,看了下面的例子,就会感觉到非常的奇妙。ITPUB个人空间v1|N?)w#gsE
ITPUB个人空间rWuU'U0Bb
namespace ExtMethodITPUB个人空间 J$~JWZI
{ITPUB个人空间x+A$`%D3F9K
public class Class1ITPUB个人空间#na)feu
{ITPUB个人空间U;A f SFu T
public String s = "bill";
4tG,B0U}O.a*X0 }
*__zO1_vW'_1s)w.]0 public class Class2 : Class1ITPUB个人空间,]6~0F4Z[z-pN+} q
{
t/U-k&yW+me0 }ITPUB个人空间x1G9ed]5iHPyA
public static class AnyClassName
U[;Hd7G\0 {ITPUB个人空间n8LB-@pfx(B
public static String getName(this Class1 class1)
+il%i-By U:|0 {ITPUB个人空间B{0Wn~.e(i}7R
return class1.s + class1.s; ITPUB个人空间r"gK Z2n,\
}ITPUB个人空间S(V.y+O8mK
}ITPUB个人空间rp F K~[*w
ITPUB个人空间x#M8u9T5}_A
public partial class Form1 : Form
)W v G;p^v0 {ITPUB个人空间cN#hrw5a2N
bS8w ^ UH%B(a6k#]r|0 private void button1_Click(object sender, EventArgs e)ITPUB个人空间Pdt*B3pC)sd{
{ITPUB个人空间+b(q/_LB%X%P
Class1 c = new Class1();ITPUB个人空间M2H0Ml(Q1A&gg
MessageBox.Show(c.getName()); ITPUB个人空间+^8N t]|&L:A
Class2 c = new Class2();
rrA!X{ D rD0 MessageBox.Show(c.getName());
,H*i V0gqe%vh0 }ITPUB个人空间 cO*~ig
}
9kBt!Mxf0}
(Xd1y3uW1uMo]0
{/b E.@N%J"X0 看到上面的代码,也许很多人会感到奇怪,在Class1和Class2中并没有getName方法,怎么在调用时出来个getName方法呢?实际上,这就是扩展方法的用法,从本质上说,扩展方法就是将静态方法(必须声明成static)插入到某个类和其子类中(也就是说,在这些类中可以使用在外部定义的静态方法)。那么要往哪个类中插入呢?这就要在定义静态方法时指定了。大家可以看看getName方法的第一个参数,使用了this关键字,这就表明这个方法是一个扩展方法,后面的类型就是要插入该方法的类,在本例中是Class1,也就是说在Class1及其子类中都可以使用getName方法。上面的调用代码也相当于下面的代码:
H6_I ffc0Class2 c = new Class2();ITPUB个人空间P7w5LL,T
MessageBox.Show(AnyClassName.getName(c));ITPUB个人空间\+_!|'B:eta
7s~X f5bL0p2Kr0 但使用c.getName可能会更好一些,而且也降低了对静态方法所在的类(AnyClassName)的依赖性。
a8Wby-XN f9mA0
IWSmBaS/b0 在使用扩展方法时应注意以下几点:
]Qe[5c-qGU0
LnC-hZ5R*i+@Ub@l01. 扩展方法所在的类名可以是任意合法的类名。ITPUB个人空间0n c { }j6@,F
9o5} N3X!nc0r'~02. 扩展方法所在的类必须和使用扩展方法的代码在同一个命名空间里,否则无法编译通过。
z*J.q x3KZ-[yKe0ITPUB个人空间S)m uX/r7O+gJ[%k
3. 在本例中,Class1和Class2只能声明成public,因为AnyClassName被声明为public。如果AnyClassName不加修饰符,Class1和Class2也可以不加修饰符,当然,也可以被声明为public。也就是说,Class1和Class2必须有比AnyClassName具有更强的访问性。如下面代码所示:ITPUB个人空间]h8seI"? x4R)m2o"n
class Class1
9zr IbL4Dy0 {
?Hv"L}'JT0 public String s = "bill";
?n#O0e8NE+m3~0 }ITPUB个人空间4]v%wz.R:H~z7iV
class Class2 : Class1ITPUB个人空间&}| }l4OGgD
{ITPUB个人空间'Ic|l ?}Y,E
}ITPUB个人空间+L*q^4q!G#Y*@
static class AnyClassName // 这时如果前面加public是无法编译通过的。
zc5~5HDt;bk0 {
w ZLYdaC0 public static String getName(this Class1 class1)ITPUB个人空间 @TK&Wz;\Qn
{
"w2z2t9gF#Rk@0 return class1.s + class1.s; ITPUB个人空间K&y[yuJ.D
}ITPUB个人空间@,k-Q0cNi1fr7xk%U
}ITPUB个人空间 uml A0fRJ+y
U9G _:B q r@04. 如果在Class1或Class2中已经有getName方法了,那么Class1或Class2中的getName优先级更高。也就是说,扩展方法是无法覆盖原类中的同名(参数名和类型也相同)的方法的。
qu-dm#[]0ITPUB个人空间}-W5]T [,o f
扩展方法尤其在很多类需要同样的方法,而这些类又无法继承其它类时特别有用。当然,在要对某个类进行扩展,但我们并没有源代码时,扩展方法也可以派上用场。
-
itpub小尾巴鱼发布于2008-06-17 23:24:16
-
o

