2008年4月19日星期六

看看属性被变异(编译)后的样子……

准备工作

其实没有什么准备工作,不过可以看看《关于打开ILDASM的方法(2种)》,或许对您有用。

 

前言

本来没有这个前言的,刚才自己看了标题,感觉有属性大全的味道,顺便改了标题,很可惜这里不讲那些你需要基础知识,那些知识您可以从MSDN获取。本文究竟讲些什么呢?本文其实没讲什么,就想看看属性被“编译”(变异)后的样子……

 

关于属性

get、set访问器

在使用了get、set访问器后,同类中不能够定义名称为get_[PropertyName]()与set_[PropertyName](TypeOfProperty value)这样的方法,否则将遭遇编译错误,如下图所示:

image

通过ILDASM工具查看后方可知道,get和set访问器会被编译器编译成依照上述规则而转换的公有方法供外部调用,这时我们若定义了相同签名的方法体将导致编译器的编译结果违背最基本的定义规则。

image 

自动实现的属性

众所周知在.NET 3.0的新版本中增加了自动实现的属性(automatically implemented property)语言特性。这将带来形如下面这样的属性声明方式:

        public int DotNet3Field1
{
get;
set;
}


那么它将如何编译呢?同样用ILDASM查看:



image



在图中我们可以很容易看到它通过了'<PropertyName>k__BackingField'的方式进行了声明。关于自动实现的属性的限制,请参看《自动实现的属性》而这样的方式避免了之前编译错误的尴尬,因为由编译器生成的字段名不符合我们的语言规范。



索引器



为了说明问题以下仅依照索引器的定义规范实现索引器,但不保证索引器能够正常工作:



        public int this[int index]
{
get {
return 0;
}
set {
}
}


image



仔细对比就可以看见多了



.custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = (01 00 04 49 74 65 6D 00 00)



get_Item : int32(int32)



set_Item : void(int32,int32)



Item : instance int32(int32)



以下分别是get_Item和set_Item的IL代码



.method public hidebysig specialname instance int32 
get_Item(int32 index) cil managed
{
// 代码大小 7 (0x7)
.maxstack 1
.locals init ([0] int32 CS$1$0000)
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret
} // end of method BaseClass::get_Item

.method public hidebysig specialname instance void
set_Item(int32 index,
int32 'value') cil managed
{
// 代码大小 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method BaseClass::set_Item


因此其实索引器与属性之间的唯一差别仅在于参数的个数上,当然外部表现还有那个中括号。

没有评论: