c#和c++之间一个显著的区别是它提供了对元数据的支持:有关类、对象、方法等其他实体的数据。属性可以分为二类:一类以clr的一部分的形式出现,另一种是我们自己创建的属性,clr属性用来支持串行化、排列和com协同性等。一些属性是针对一个组合体的,有些属性则是针对类或界面,它们也被称作是属性目标。 
将属性放在属性目标前的方括号内,属性就可以作用于它们的属性目标。
[assembly:assemblydelaysign(false)] 
 [assembly:assemblykeyfile(".//keyfile.snk")] 
或用逗号将各个属性分开:
[assembly:assemblydelaysign(false), 
 assembly:assemblykeyfile(".//keyfile.snk")] 
自定义的属性 
 
我们可以任意创建自定义属性,并在认为合适的时候使用它们。假设我们需要跟踪bug的修复情况,就需要建立一个包含bug的数据库,但需要将bug报告与专门的修正情况绑定在一块儿,则可能在代码中添加如下所示的注释:
//bug323fixedbyjesseliberty1/1/2005.
这样,在源代码中就可以一目了然地了解bug的修正情况,但如果如果把相关的资料保存在数据库中可能会更好,这样就更方便我们的查询工作了。如果所有的bug报告都使用相同的语法那就更好了,但这时我们就需要一个定制的属性了。我们可能使用下面的内容代替代码中的注释:
[bugfix(323,"jesseliberty","1/1/2005")comment="offbyoneerror"]
与c#中的其他元素一样,属性也是类。定制化的属性类需要继承system.attribute:
publicclassbugfixattribute:system.attribute
我们需要让编译器知道这个属性可以跟什么类型的元素,我们可以通过如下的方式来指定该类型的元素:
[attributeusage(attributetargets.classmembers,allowmultiple=true)]
attributeusage是一个作用于属性的属性━━元属性,它提供的是元数据的元数据,也即有关元数据的数据。在这种情况下,我们需要传递二个参数,第一个是目标(在本例中是类成员。),第二个是表示一个给定的元素是否可以接受多于一个属性的标记。allowmultiple的值被设置为true,意味着类成员可以有多于一个bugfixattribute属性。如果要联合二个属性目标,可以使用or操作符连接它们。
[attributeusage(attributetargets.class|attributetargets.interface,allowmultiple=true)]
上面的代码将使一个属性隶属于一个类或一个界面。
新的自定义属性被命名为bugfixattribute。命名的规则是在属性名之后添加attribute。在将属性指派给一个元素后,编译器允许我们使用精简的属性名调用这一属性。因此,下面的代码是合法的:
[bugfix(123,"jesseliberty","01/01/05",comment="offbyone")]
编译器将首先查找名字为bugfix的属性,如果没有发现,则查找bugfixattribute。
每个属性必须至少有一个构造器。属性可以接受二种类型的参数:环境参数和命名参数。在前面的例子中,bugid、编程人员的名字和日期是环境参数,注释是命名参数。环境参数被传递到构造器中的,而且必须按在构造器中定义的顺序传递。
publicbugfixattribute(intbugid,stringprogrammer,stringdate) 
 { 
 this.bugid=bugid; 
 this.programmer=programmer; 
 this.date=date; 
 } 
namedparametersareimplementedasproperties.
属性的使用 
 
为了对属性进行测试,我们创建一个名字为mymath的简单类,并给它添加二个函数,然后给它指定bugfix属性。
[bugfixattribute(121,"jesseliberty","01/03/05")]
[bugfixattribute(107,"jesseliberty","01/04/05", 
 comment="fixedoffbyoneerrors")] 
 publicclassmymath 
这些数据将与元数据存储在一起。下面是完整的源代码及其输出:
自定义属性
usingsystem; 
 //创建被指派给类成员的自定义属性 
 [attributeusage(attributetargets.class, 
 allowmultiple=true)] 
 publicclassbugfixattribute:system.attribute 
 { 
 //位置参数的自定义属性构造器 
 publicbugfixattribute 
 (intbugid, 
 stringprogrammer, 
 stringdate) 
 { 
 this.bugid=bugid; 
 this.programmer=programmer; 
 this.date=date; 
 } 
 publicintbugid 
 { 
 get 
 { 
 returnbugid; 
 } 
 } 
//命名参数的属性 
 publicstringcomment 
 { 
 get 
 { 
 returncomment; 
 } 
 set 
 { 
 comment=value; 
 } 
 } 
publicstringdate 
 { 
 get 
 { 
 returndate; 
 } 
  } 
publicstringprogrammer 
 { 
 get 
 { 
 returnprogrammer; 
 } 
 } 
//专有成员数据 
 privateintbugid; 
 privatestringcomment; 
 privatestringdate; 
 privatestringprogrammer; 
 } 
//把属性指派给类
[bugfixattribute(121,"jesseliberty","01/03/05")] 
 [bugfixattribute(107,"jesseliberty","01/04/05", 
 comment="fixedoffbyoneerrors")] 
 publicclassmymath 
 { 
publicdoubledofunc1(doubleparam1) 
 { 
 returnparam1+dofunc2(param1); 
 } 
publicdoubledofunc2(doubleparam1) 
 { 
 returnparam1/3; 
 } 
}
publicclasstester 
 { 
 publicstaticvoidmain() 
 { 
 mymathmm=newmymath(); 
 console.writeline("callingdofunc(7).result:{0}", 
 mm.dofunc1(7)); 
 } 
 } 
输出:
callingdofunc(7).result:9.3333333333333339
象我们看到的那样,属性对输出绝对没有影响,创建属性也不会影响代码的性能。到目前为止,读者也只是在听我论述有关属性的问题,使用ildasm浏览元数据,就会发现属性确实是存在的。
新闻热点
疑难解答