在.NET框架中,经常用到属性,从定义哪些类是可序列化到选择某个Web服务应用中的哪些方法是可以公开的都会用到属性。
使用属性可以在设计时对类、properties和方法添加说明,然后在运行时通过反射信息来检查它们。本文为我们介绍了在开发应用时如何利用C#自定义属性。
本文可以从技术文章下载出获得,其中包含了一个使用定制属性的Visual Studio项目示例文件。
属性类是设计时可应用于类、properties和方法的特殊文类。属性类提供描述元素某些方面属性的方式或决定依附于该元素的其它类的行为,进而在运行时可以访问和检验这些描述与行为。你可以将属性类看作为类成员添加特殊修改器的一种方式。
例如,如果你曾经写过Web服务,那肯定知道要使得方法在整个服务中是公开的,必须要使用WebMethod属性。这是一个演示属性应用的很好的例子,因为我们要用WebMethod属性扩展编程模型。C#中没有内建的方式来指定某个方法通过Web服务是可见的(因为内建有表明一个方法是私有的方式),因此需要添加WebMethod属性来满足这一需要。
设计自定义属性
设计自定义属性的过程十分简单,在设计属性前只需要考虑以下几个方面:
使用属性的目的是什么?
属性可以以很多方式使用。你需要定义属性到底要完成什么功能并确保这些特定功能没有内建在.NET框架集中。使用.NET修改器要比使用属性好,因为这将简化同其它装配件的集成过程。
属性必须储存什么信息?
属性是打算用来指示某个功能的简单标志吗?或者属性是否要储存信息?一个属性可以拥有设计时赋予的一组信息,并在运行时查看这些信息。例如,看一下示例应用中的别名属性。
属性应该驻留在哪个装配件中?
大多数情况下,可以将属性包含在使用该属性的装配件中。不过也有这样的例子,将属性驻留在公共的、轻量级的、共享装配件中会更好些。这种类型的配置允许客户使用属性时不必引用不需要的装配件。
哪些装配件将会识别属性?
如果没有模块读取属性,那么它将一文不值。你很可能将读取属性的类放在属性驻留的同一个装配件中。然而,正像前面提到的,也有这样的例子,你想将读取属性的方法与属性自身分别放在不同的装配件中。
使用属性
在我们深入了解如何设计自定义属性之前,我们需要先看一下它们是如何使用的。例如,假定我们有一个称为“Hide”的属性它能够有效地隐藏Properties,因此它们不会显示在屏幕上。如果我们将这个属性应用于“SSN”property,那么代码将会如列表A所示。
列表 A
[Hide ()]
public string SSN
{
get { return _ssn; }
set { _ssn = value; }
}
作为更复杂一点的例子,假设我们将有一个属性称为“Alias”。该属性的任务是检查一个property可能拥有别名。这将允许将一个property值映射给另一个property即使批roperty的名字不匹配。这个属性接受一系列字符串值作为映射名。(列表B)[Page]
列表 B
[Alias (\"FirstName\", \"First\")]
public string FName
{
get { return _fName; }
set { _fName = value; }
}
在这个例子中,property“FName”被映射到“FirstName”和“First”,请查看示例应用以更详细的了解这种应用。
创建属性
创建属性是一个简单的过程。你可以定义继承自System.Attribute类的一个包含你想要储存的数据的类。列表C的前半部分显示了如何创建一个名为“Alias”的属性。
列表 C
Class Alias : System.Attribute
{
string[] _names;
public Alias(params string[] names)
{
this.Names = names;
}
public string[] Names
{
get { return _names; }
set { _names = value; }
}
}
正如你所看到的,这就是一个普通的类,唯一的例外就是继承自System.Attribute类。我们不需要作任何特别的事情使它成为一个类。我们只是简单的定义了一个需要使用的构造函数并创建了一个property和一个存储数据的私有成员。
列表D是个更简单的属性——“Hide”属性。这个属性不需要构造函数(使用默认的构建函数),也不储存数据。因为这个属性只是一个简单的标志类型的属性。
列表 D
Class Hide : System.Attribute
{
//This is a simple attribute, that only requires
// the default constructor.
}
从代码中读取属性
读取属性并检查其中的数据比使用属性或创建属性显著地更加复杂。读取属性要求开发人员要对如何使用一个对象的反射信息有个基本了解。如果你不熟悉反射机制,可以阅读“应用反射”系列文章。
假设我们正在查看一个类,我们想知道该类的那个properties使用了Alias属性以及都有哪些别名。列表E实现了这个功能。
列表 E
Private Dictionary<string, string> GetAliasListing(Type destinationType)
{