属性是编程中用于提供额外信息的一种机制。它们可以附加到方法、类、命名空间、程序集等上。属性使得开发者在调用方法或访问类时,能够直观地看到相关信息,并据此做出相应的操作。
例如,下面是一个简单的类,其中“Method1”方法被“Obsolete”属性装饰。属性通过使用“[]”符号来定义。因此,当开发者开始在这个类中编码时,他们会收到警告,提示“Method1”已经过时,现在应该使用“NewMethod1”。
public class Class1 {
[Obsolete]
public void Method1() {
}
public void NewMethod1() {
}
}
同样地,如果有人尝试创建“Class1”的对象,他们会在工具提示中收到警告,提示“Method1”已经过时,应该使用“NewMethod1”。简而言之,属性是嵌入在代码中的一小段信息,开发者可以直观地看到这些信息。
如果想向开发者显示一些信息,可以在“Obsolete”属性中传递消息,如下所示:
[Obsolete("Please use NewMethod1")]
public void Method1() {
}
如果想更加严格,不允许开发者使用该方法,可以向“Obsolete”属性传递“true”,如下所示:
[Obsolete("Please use NewMethod1", true)]
public void Method1() {
}
现在,如果开发者尝试调用“Method1”,他们将收到错误,而不仅仅是一个简单的警告。
之前讨论的“Obsolete”属性是一个现成的属性。要创建自定义属性,需要继承自Attribute类。下面是一个简单的“HelpAttribute”,它有一个“HelpText”属性。
class HelpAttribute : Attribute {
public string HelpText { get; set; }
}
“HelpAttribute”被应用到“Customer”类上,如下所示。现在,当开发者看到这个类时,他们可以直观地看到信息。
[Help(HelpText = "This is a class")]
class Customer {
private string _CustomerCode;
[Help(HelpText = "This is a property")]
public string CustomerCode {
get { return _CustomerCode; }
set { _CustomerCode = value; }
}
[Help(HelpText = "This is a method")]
public void Add() {
}
}
通过使用“AttributeUsage”和“AttributeTargets”,可以将属性限制在特定的部分,如类、方法、属性等。下面是一个简单的自定义属性,现在仅限于方法。
[AttributeUsage(AttributeTargets.Method)]
class HelpAttribute : Attribute {
public string HelpText { get; set; }
}
如果尝试将上述属性应用到类或属性上,将得到编译时错误。也可以将属性限制为类、构造函数、程序集等。以下是可以限制属性的一些可能性。
到目前为止讨论的一个用途是为开发者提供信息,以便他们在编码时可以看到并据此做出决策。另一个用途是可以通过反射以编程方式读取信息并据此采取行动。
例如,下面是一个自定义属性,它描述了类属性的字符长度。
[AttributeUsage(AttributeTargets.Property)]
class Check : Attribute {
public int MaxLength { get; set; }
}
下面是一个客户类,该属性被装饰,提供了“CustomerCode”属性的最大长度不能超过10个字符的信息。
class Customer {
private string _CustomerCode;
[Check(MaxLength = 10)]
public string CustomerCode {
get { return _CustomerCode; }
set { _CustomerCode = value; }
}
}
接下来的代码将动态地遍历每个属性的属性,并进行长度验证检查。
第一步是创建客户类的实例。
// 创建Customer类的实例
Customer obj = new Customer();
obj.CustomerCode = "12345678901";
第二步是获取对象的“Type”。因为一旦获得了对象的类型,就可以浏览对象的属性、方法等。
// 获取对象的类型
Type objtype = obj.GetType();
使用“Type”对象,遍历所有属性及其属性。
// 遍历所有属性
foreach (PropertyInfo p in objtype.GetProperties()) {
// 对于每个属性,遍历所有属性
foreach (Attribute a in p.GetCustomAttributes(false)) {
}
}
一旦获得了属性,可以进行长度检查,并相应地引发异常。
// 遍历所有属性
foreach (PropertyInfo p in objtype.GetProperties()) {
// 对于每个属性,遍历所有属性
foreach (Attribute a in p.GetCustomAttributes(false)) {
Check c = (Check)a;
if (p.Name == "CustomerCode") {
// 进行长度检查,并相应地引发异常
if (obj.CustomerCode.Length > c.MaxLength) {
throw new Exception("Max length issues");
}
}
}
}
是的,它们在子类中被继承。
在“AttributeUsage”中有“Inherited”属性,如果将其设置为false,那么这些属性将不会被继承到子类中。
[AttributeUsage(AttributeTargets.Property, Inherited = false)]
class Check : Attribute {
public int MaxLength { get; set; }
}
如果指定“AllowMultiple”为true,它可以在同一程序中多次使用。
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
class Check : Attribute {
public int MaxLength { get; set; }
}