C#特性(Attribute)

作者: adm 分类: C# 发布时间: 2024-03-25

特性(Attribute)是一种用于在程序运行时传递各种元素(例如类、方法、结构、枚举等)行为信息的声明性代码。使用特性可以将元数据(例如编译器指令、注释、描述、方法和类等信息)添加到程序中。.Net Framework 提供了两种类型的特性,分别是预定义特性和自定义特性。

在 C# 中,特性具有以下属性:
使用特性可以向程序中添加元数据,元数据是指程序中各种元素的相关信息,所有 .NET 程序中都包含一组指定的元数据;
可以将一个或多个特性应用于整个程序、模块或者较小的程序元素(例如类和属性)中;
特性可以像方法和属性一样接受自变量;
程序可使用反射来检查自己的元数据或其他程序中的元数据。
1、定义特性
C# 中定义特性的语法格式如下所示:
[attribute(positional_parameters, name_parameter = value, …)]
element

其中,[ ]中用来定义特性的名称和值,positional_parameters 用来指定基本信息,name_parameter 用来指定可选信息。
2、预定义特性
.Net Framework 中提供了三个预定义的属性:
AttributeUsage;
Conditional;
Obsolete。
1) AttributeUsage
预定义特性 AttributeUsage 用来描述如何使用自定义特性类,其中定义了可以应用特性的项目类型。AttributeUsage 的语法格式如下:
[AttributeUsage (
validon,
AllowMultiple = allowmultiple,
Inherited = inherited
)]

参数说明如下:
参数 validon 用来定义特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All;
参数 allowmultiple(可选参数)用来为该特性的 AllowMultiple 属性(property)提供一个布尔值,默认值为 false(单用的),如果为 true,则该特性是多用的;
参数 inherited(可选参数)用来为该特性的 Inherited 属性(property)提供一个布尔值,默认为 false(不被继承),如果为 true,则该特性可被派生类继承。

示例代码如下:
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]

2) Conditional
预定义特性 Conditional 用来标记一个方法,它的执行依赖于指定的预处理标识符。根据该特性值的不同,在编译时会起到不同的效果,例如当值为 Debug 或 Trace 时,会在调试代码时显示变量的值。

预定义特性 Conditional 的语法格式如下:
[Conditional(
conditionalSymbol
)]

例如:
[Conditional(“DEBUG”)]

【示例】下面通过示例演示预定义特性 Conditional 的使用。
#define DEBUG
using System;
using System.Diagnostics;
namespace net.yinzhong
{
class Demo
{
static void function1()
{
Myclass.Message(“Function1 函数”);
function2();
}
static void function2()
{
Myclass.Message(“Function2 函数”);
}
static void Main(string[] args)
{
Myclass.Message(“Main 函数”);
function1();
Console.ReadKey();
}
}
public class Myclass
{
[Conditional(“DEBUG”)]
public static void Message(string msg)
{
Console.WriteLine(msg);
}
}
}
运行结果如下:
Main 函数
Function1 函数
Function2 函数

3) Obsolete
预定义特性 Obsolete 用来标记不应被使用的程序,您可以使用它来通知编译器放弃某个目标元素。例如当您需要使用一个新方法来替代类中的某个旧方法时,就可以使用该特性将旧方法标记为 obsolete(过时的)并来输出一条消息,来提示我们应该使用新方法代替旧方法。

预定义特性 Obsolete 的语法格式如下:
[Obsolete (
message
)]

[Obsolete (
message,
iserror
)]

语法说明如下:
参数 message 是一个字符串,用来描述项目为什么过时以及应该使用什么替代;
参数 iserror 是一个布尔值,默认值是 false(编译器会生成一个警告),如果设置为 true,那么编译器会把该项目的当作一个错误。

【示例】下面通过示例来演示预定义特性 Obsolete 的使用:
using System;
namespace net.yinzhong
{
class Demo
{
[Obsolete(“OldMethod 已弃用,请改用 NewMethod”, true)]
static void OldMethod()
{
Console.WriteLine(“已弃用的函数”);
}
static void NewMethod()
{
Console.WriteLine(“新定义的函数”);
}
static void Main(string[] args)
{
OldMethod();
}
}
}
运行结果如下:
demo.cs(18,10): error CS0619: “net.yinzhong.Demo.OldMethod()”已过时:“OldMethod 已弃用,请改用 NewMethod”

3、自定义特性
.Net Framework 允许您创建自定义特性,自定义特性不仅可以用于存储声明性的信息,还可以在运行时被检索。创建并使用自定义特性可以分为四个步骤:
声明自定义特性;
构建自定义特性;
在目标程序上应用自定义特性;
通过反射访问特性。

最后一步涉及编写一个简单的程序来读取元数据以便查找各种符号。元数据是有关数据或用于描述其他数据信息的数据。该程序应在运行时使用反射来访问属性。
1) 声明自定义属性
自定义特性应该继承 System.Attribute 类,如下所示:
// 一个自定义特性 BugFix 被赋给类及其成员
[AttributeUsage(
AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]

public class DeBugInfo : System.Attribute

在上面的示例代码中,我们声明了一个名为 DeBugInfo 的自定义属性。
2) 构建自定义特性
让我们构建一个名为 DeBugInfo 的自定义特性,该特性可以存储下面列举的调试信息:
bug 的代码编号;
该 bug 的开发人员名字;
上次审查代码的日期;
一个存储了开发人员标记的字符串消息。

DeBugInfo 类中带有三个用于存储前三个信息的私有属性(property)和一个用于存储消息的公有属性(public)。所以 bug 编号、开发人员名字和审查日期将是 DeBugInfo 类的必需的定位( positional)参数,而消息则是一个可选的命名(named)参数。

每个特性都至少有一个构造函数,而且定位( positional)参数需要通过构造函数传递。如下例所示:
// 一个自定义特性 BugFix 被赋给类及其成员
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
public class DeBugInfo : System.Attribute
{
private int bugNo;
private string developer;
private string lastReview;
public string message;
public DeBugInfo(int bg, string dev, string d)
{
this.bugNo = bg;
this.developer = dev;
this.lastReview = d;
}
public int BugNo
{
get
{
return bugNo;
}
}
public string Developer
{
get
{
return developer;
}
}
public string LastReview
{
get
{
return lastReview;
}
}
public string Message
{
get
{
return message;
}
set
{
message = value;
}
}
}
3) 应用自定义特性
通过把特性放置在紧挨着它的目标上面来应用该特性,示例代码如下:
纯文本复制
using System;
namespace net.yinzhong
{
class Demo
{
static void Main(string[] args)
{
Rectangle rec = new Rectangle(12, 15);
rec.Display();
}
}
[DeBugInfo(45, “Zara Ali”, “12/8/2012”, Message = “返回值类型不匹配”)]
[DeBugInfo(49, “Nuha Ali”, “10/10/2012”, Message = “未使用变量”)]
class Rectangle
{
// 成员变量
protected double length;
protected double width;
public Rectangle(double l, double w)
{
length = l;
width = w;
}
[DeBugInfo(55, “Zara Ali”, “19/10/2012”,
Message = “返回值类型不匹配”)]
public double GetArea()
{
return length * width;
}
[DeBugInfo(56, “Zara Ali”, “19/10/2012”)]
public void Display()
{
Console.WriteLine(“Length: {0}”, length);
Console.WriteLine(“Width: {0}”, width);
Console.WriteLine(“Area: {0}”, GetArea());
}
}
// 一个自定义特性 BugFix 被赋给类及其成员
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
public class DeBugInfo : System.Attribute
{
private int bugNo;
private string developer;
private string lastReview;
public string message;
public DeBugInfo(int bg, string dev, string d)
{
this.bugNo = bg;
this.developer = dev;
this.lastReview = d;
}
public int BugNo
{
get
{
return bugNo;
}
}
public string Developer
{
get
{
return developer;
}
}
public string LastReview
{
get
{
return lastReview;
}
}
public string Message
{
get
{
return message;
}
set
{
message = value;
}
}
}
}
运行结果如下:
Length: 12
Width: 15
Area: 180

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!