(转)C#中 特性(attribute)的用法

摘要:
在C#中使用预定义的属性“让我们来看看如何在代码中使用预定义的属性。使用属性后缀作为属性类名是一种惯例:编译器将首先在System.Attribute的派生类中找到添加的属性类。我们已经向HelpAttribute属性类添加了一个属性,并将在后续部分的运行时环境中查找它tity自定义属性应该放在前面。

定义

正如MSDN中所描述的那样-----

“特性是被指定给某一声明的一则附加的声明性信息。”

使用预定义(Pre-defined)特性

在C#中,有一个小的预定义特性集合。在学习如何建立我们自己的定制特性(custom attributes)之前,我们先来看看在我们的代码中如何使用预定义特性。

using System;
public class AnyClass
{
[Obsolete("Don't use Old method, use New method", true)]
static void Old( ) { }

static void New( ) { }

public static void Main( )
{
Old( );
}
}
我们先来看一下上面这个例子,在这个例子中我们使用了Obsolete特性,它标记了一个不应该再被使用的程序实体。第一个参数是一个字符串,它解释了为什么该实体是过时的以及应该用什么实体来代替它。实际上,你可以在这里写任何文本。第二个参数告诉编译器应该把使用这个过时的程序实体当作一种错误。它的默认值是false,也就是说编译器对此会产生一个警告。

当我们尝试编译上面这段程序的时候,我们将会得到一个错误:

AnyClass.Old()' is obsolete: 'Don't use Old method, use New method'

开发定制特性(custom attributes)

现在让我们来看看如何开发我们自己的特性。

首先我们要从System.Attribute派生出我们自己的特性类(一个从System.Attribute抽象类继承而来的类,不管是直接还是间接继承,都会成为一个特性类。特性类的声明定义了一种可以被放置在声明之上新的特性)。

using System;
public class HelpAttribute : Attribute
{
}
不管你是否相信,我们 已经建立了一个定制特性,现在我们可以用它来装饰现有的类就好像上面我们使用Obsolete attribute一样。

[Help()]
public class AnyClass
{
}
注意:对一个特性类名使用Attribute后缀是一个惯例。然而,当我们把特性添加到一个程序实体,是否包括Attribute后缀是我们的自由。编译器会首先在System.Attribute的派生类中查找被添加的特性类。如果没有找到,那么编译器会添加Attribute后缀继续查找。

到目前为止,这个特性还没有起到什么作用。下面我们来添加些东西给它使它更有用些。

using System;
public class HelpAttribute : Attribute
{
public HelpAttribute(String Descrition_in)
{
this.description = Description_in;
}
protected String description;
public String Description
{
get
{
return this.description;

}
}
}
[Help("this is a do-nothing class")]
public class AnyClass
{
}
在上面的例子中,我们给HelpAttribute特性类添加了一个属性并且在后续的部分中我们会在运行时环境中查寻它。

定义或控制特性的使用

AttributeUsage类是另外一个预定义特性类,它帮助我们控制我们自己的定制特性的使用。它描述了一个定制特性如和被使用。

AttributeUsage有三个属性,我们可以把它放置在定制属性前面。第一个属性是:

ValidOn

通过这个属性,我们能够定义定制特性应该在何种程序实体前放置。一个属性可以被放置的所有程序实体在AttributeTargets enumerator中列出。通过OR操作我们可以把若干个AttributeTargets值组合起来。

AllowMultiple

这个属性标记了我们的定制特性能否被重复放置在同一个程序实体前多次。

Inherited

我们可以使用这个属性来控制定制特性的继承规则。它标记了我们的特性能否被继承。

下面让我们来做一些实际的东西。我们将会在刚才的Help特性前放置AttributeUsage特性以期待在它的帮助下控制Help特性的使用。

using System;
[AttributeUsage(AttributeTargets.Class), AllowMultiple = false,
Inherited = false ]
public class HelpAttribute : Attribute
{
public HelpAttribute(String Description_in)
{
this.description = Description_in;
}
protected String description;
public String Description
{
get
{
return this.description;
}
}
}
先让我们来看一下AttributeTargets.Class。它规定了Help特性只能被放在class的前面。这也就意味着下面的代码将会产生错误:

[Help("this is a do-nothing class")]
public class AnyClass
{
[Help("this is a do-nothing method")] //error
public void AnyMethod()
{
}
}
编译器报告错误如下:

AnyClass.cs: Attribute 'Help' is not valid on this declaration type.

It is valid on 'class' declarations only.

我们可以使用AttributeTargets.All来允许Help特性被放置在任何程序实体前。可能的值是:

Assembly,
Module,
Class,
Struct,
Enum,
Constructor,
Method,
Property,
Field,
Event,
Interface,
Parameter,
Delegate,
All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | Event | Interface | Parameter | Delegate,
ClassMembers = Class | Struct | Enum | Constructor | Method | Property | Field | Event | Delegate | Interface )
下面考虑一下AllowMultiple = false。它规定了特性不能被重复放置多次。

[Help("this is a do-nothing class")]
[Help("it contains a do-nothing method")]
public class AnyClass
{
[Help("this is a do-nothing method")] //error
public void AnyMethod()
{
}
}
它产生了一个编译期错误。

AnyClass.cs: Duplicate 'Help' attribute

Ok,现在我们来讨论一下最后的这个属性。Inherited, 表明当特性被放置在一个基类上时,它能否被派生类所继承。

[Help("BaseClass")]
public class Base
{
}

public class Derive : Base
{
}
这里会有四种可能的组合:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false ]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false ]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true ]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true ]
第一种情况:

如果我们查询(Query)(稍后我们会看到如何在运行期查询一个类的特性)Derive类,我们将会发现Help特性并不存在,因为inherited属性被设置为false。

第二种情况:

和第一种情况相同,因为inherited也被设置为false。

第三种情况:

为了解释第三种和第四种情况,我们先来给派生类添加点代码:

[Help("BaseClass")]
public class Base
{
}
[Help("DeriveClass")]
public class Derive : Base
{
}
现在我们来查询一下Help特性,我们只能得到派生类的属性,因为inherited被设置为true,但是AllowMultiple却被设置为false。因此基类的Help特性被派生类Help特性覆盖了。

第四种情况:

在这里,我们将会发现派生类既有基类的Help特性,也有自己的Help特性,因为AllowMultiple被设置为true。

免责声明:文章转载自《(转)C#中 特性(attribute)的用法》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SPCOMM控件对串口参数的设置大数据测试总结下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

WebView2简单试用(四)—— 使用固定版本的Edge Runtime

Edge Runtime支持两种模式:长绿(All Green)和固定版本(Fixed Version)这两种方式和vc runtime安装比较类似。 长绿版本可以作为独立的安装包安装,所有程序共享。固定版本则也可以直接在程序中包含。 长绿版本的优势: 可以自动更新 支持在线和离线安装 所有WebView2程序共享运行时,节约磁盘空间     固定版本...

微信小程序:页面生命周期

小程序生命周期分为应用生命周期和页面生命周期 1、Onload:页面加载时触发,一般在onLoad中发送异步请求来初始化页面数据。 2、onShow:页面显示时触发 3、onReady:页面初次渲染完成时触发。 4、onHide:是页面隐藏时触发,注意不是应用隐藏,切后台时,页面就会隐藏。即整个小程序隐藏时,页面也就隐藏了。另外,在当前页面跳转的时候也相...

ECMAScript正则表达式6个最新特性

译者按: 还没学好ES6?ECMAScript 2018已经到来啦! 原文:ECMAScript regular expressions are getting better! 作者: Mathias Bynens: Google V8引擎开发者 译者:Fundebug 为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译...

微信小程序&mpvue问题总结(1)

微信小程序进入到首页的时候,日志打印出“created”, “onlaunch”, “mounted”,具体代码如下:那么,在小程序中 created() 和 mounted() 究竟什么时刻被调用 首页: created () { console.log('created') }, mounted () { console....

dotnet 判断程序当前使用管理员运行降低权使用普通权限运行

有一些程序是不想通过管理员权限运行的,因为在很多文件的读写,如果用了管理员权限程序写入的程序,其他普通权限的程序是无法直接访问的。本文告诉大家如何判断当前的程序是通过管理员权限运行,然后通过资源管理器使用普通权限运行 通过下面代码可以判断当前的程序是管理员权限运行 var identity = WindowsIdentity.Get...

JAVA转义字符

JAVA中转义字符2009-08-12 17:40JAVA中转义字符: 1.八进制转义序列:\ + 1到3位5数字;范围'\000'~'\377' \0:空字符 2.Unicode转义字符:\u + 四个十六进制数字;0~65535 \u0000:空字符 3.特殊字符:就3个 \":双引号 \':单引号 \\:反斜线 4.控制字符:5个...