C#_Attribute


Attribute

Attribute,一般翻译成 特性 (与Property属性做区分)。
它提供了一种将 元数据(metadata) (声明性信息)与代码(程序集、类型、方法、属性等)关联起来的强大方法。在Attribute与程序实体关联之后,可以在运行时使用 反射(reflection) 技术查询该Attribute。

元数据
元数据是描述数据的数据。
在C#编程环境中,它指的是用于描述程序代码的特性。
机智的小伙伴会问,描述程序代码?那不是注释嘛。
这边有个本质区别,注释通常不会影响程序的执行,编译器在编译过程中会忽略注释;而元数据是数据,可以通过反射等技术在程序运行时查询和操作。

Attribute有以下性质:

  • Attribute会将元数据添加至程序。 Metadata(元数据) 是一种关于程序中定义的类型的信息。所有的.NET程序集都包含一组指定的元数据,用于描述程序中定义的类型和类成员。你可以添加自定义的Attribute来指定所需的附加信息。
  • 可以将一个或多个Attribute应用于整个程序集、模块或更小的程序元素(类、属性之类的)。
  • Attribute可以像方法和属性一样接收参数。
  • 可以在程序中使用反射来检查元数据。

反射提供类型为Type的对象来描述程序集、模块和类型。你可以使用反射来动态地创建类的实例,将类绑定到现有的对象,或从现有对象获取类型并调用其方法或访问其字段和属性。若你在代码中使用Attribute,则你可以用反射访问它们。

下面是一个简单的反射示例,使用GetType()方法(所有继承自Object的类都可以用)获取变量的类型:

注意
用之前要在 .cs 文件顶部添加 using system;using System.Reflection;

// using GetType to obtain type information
int i = 42;
Type type = i.GetType();
Console.WriteLine(type);

输出: System.Int32

下面示例使用反射获取加载程序集的全名:

// using Reflection to get information of an Assembly
Assembly info = typeof(int).Assembly;
Console.WriteLine(info);

输出:System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e

扫描二维码关注公众号,回复: 15454707 查看本文章

注意
C#关键字 protectedinternal 在中间语言(IL)中没有意义,也不会在反射API中起作用。在IL中对应的术语是 FamilyAssembly。要用反射识别internal方法,使用 IsAssembly 属性。要识别 protected internal 方法,使用 IsFamilyOrAssembly。

使用Attribute

Attribute几乎可以放在任何声明上,尽管特定的Attribute可能会限制其有效的声明类型。在C#中,可以通过将Attribute名称用方括号[]括起来,置于该Attribute所应用的实体声明上来指定一个Attribute。

下面示例中, SerializableAttribute Attribute用于给类指定一个特性(该类的对象将被序列化):

[Serializable]
public class SampleClass
{
    
    
	// objects of this type can be serialized.
}

下面示例声明了一个带有 DllImportAttribute Attribute的方法:

[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static void SampleMethod();

一个声明中也可以放置多个Attribute,如下:

void MethodA([In][Out] ref double x) {
    
     }
void MethodB([Out][In] ref double x) {
    
     }
void MethodC([In, Out] ref double x) {
    
     }

有些Attribute也可以为给定实体指定多次。下面是一个多重使用的Attribute例子(ConditionalAttribute):

[Conditional("DEBUG"), Conditional("TEST1")]
void TraceMethod()
{
    
    
	// ...
}

注意
按照惯例,所有Attribute名称都以"Attribute"结尾,以区别于.NET库中的其它项。但是,在代码中使用Attribute时,不需要指定Attribute后缀。例如[DllImport]等价于[DllImportAttribute],但是DllImportAttribute是Attribute在.NET类库中的实际名称。

Attribute参数

许多Attribute都有参数,这些参数可能是位置参数(positional)、未命名参数(unnamed)或命名参数(named)。位置参数必须按一定顺序指定,且不能省略。命名参数是可选的,可以按任意顺序指定。下面三个Attribute是等价的:

[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]

其中的第一个参数DLL名称,它是位置参数,总是排在第一位;其它参数都是命名参数。在该情况下,两个默认参数默认为false,因此可以省略。位置参数对应于Attribute构造函数的参数(列表)。命名参数或可选参数对应于Attribute的属性(property)或字段(field)。

Attribute目标

Attribute的目标(target)指该Attribute所应用的实体。Attribute可以应用于类、特定的方法或整个程序集。默认情况下,Attribute应用于它后面的元素。但你也可以显式地标识一个Attribute是应用于方法,还是它的参数或其返回值。

要显式标识Attribute目标,使用以下语法:

[target : attribute-list]

target的可能值如下表所示:

Target值 应用目标
assembly 整个程序集
module 当前程序模块
field 类或结构中的字段
event 事件
method 方法或get和set属性访问器
param 方法参数或set属性访问器参数
property 属性
return 方法的返回值、属性索引或get属性访问器
type 结构体、类、接口、枚举或委托

你可以指定字段目标值,以将Attribute应用到自动实现属性(auto-implemented property)创建的后台字段。

以下示例展示了如何将Attribute应用于程序集和模块。

using System;
using System.Reflection;
[assembly: AssemblyTitleAttribute("Production assembly 4")]
[module: CLSCompliant(true)]

下面示例展示如何在C#中将Attribute应用于方法、方法参数和方法返回值。

// default: applies to method
[ValidatedContract]
int Method1() {
    
     return 0; }

// applies to method
[method: ValidatedContract]
int Method2() {
    
     return 0; }

// applies to parameter
int Method3([ValidatedContract] string contract) {
    
     return 0; }

// applies to return value
[return: ValidatedContract]
int Method4() {
    
     return 0; }

注意
无论 ValidatedContract被定义为作用于哪些目标,都必须指定 return 目标,即使 ValidatedContract 被定义为只应用于返回值。换句话说,编译器不会使用 AttributeUsage 信息来解析不明确的 Attribute 目标。

Attribute的常见使用

下面列出了代码中Attribute的常见使用:

  • 使用Web服务中的 WebMethod Attribute 来标记方法,以指示该方法可以通过SOAP协议调用。
  • 描述与本机代码交互时如何封装方法参数。
  • 描述类、方法和接口的COM属性。
  • 使用 DllImportAttribute类调用非托管代码。
  • 使用标题、版本、描述或商标描述程序集。
  • 描述为了持久化而序列化类成员。
  • 描述如何在类成员和XML节点之间映射以进行XML序列化。
  • 描述方法的安全性要求。
  • 指定用于强制安全性的特性。
  • 控制JIT的优化,使代码易于调试。
  • 获取关于方法调用者的信息。

反射概述

反射在以下情况下很有用:

  • 当需要访问程序元数据中的属性时。
  • 检查和实例化程序集中的类时。
  • 在运行时构建新的类。使用 System.Relection.Emit 中的类。
  • 执行延迟绑定,访问在运行时创建的类上的方法。

猜你喜欢

转载自blog.csdn.net/BadAyase/article/details/130708962