Attribute


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

Attribute有以下性质:

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

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

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

// 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

使用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都有参数,这些参数可能是位置参数(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的可能值如下表所示:

你可以指定字段目标值,以将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; }

Attribute的常见使用

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

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

反射概述

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

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