特性的定义
特性(Attributes)是一种声明性标记,用于向程序实体(如类、方法、属性等)添加元数据。特性提供了一种在源代码中嵌入元数据的方法,这些元数据可以在运行时通过反射来访问。
简单来说就是相当于标注附加数据。
特性的种类
内置特性
一系列用于按照对应用法使用的系统给出的特性。
过时提醒:
[Obsolete]
: 标记一个程序实体为过时的,编译器会发出警告。
[Obsolete("This method is obsolete. Use NewMethod instead.")]
public void OldMethod() { /* ... */ }
它的定义和使用:
[Obsolete(
message
)]
[Obsolete(
message,
iserror
)]
- 参数 message,是一个字符串,描述项目为什么过时以及该替代使用什么。
- 参数 iserror,是一个布尔值。如果该值为 true,编译器应把该项目的使用当作一个错误。默认值是 false(编译器生成一个警告)。
序列化提醒 :
[Serializable]
: 表示一个类可以被序列化。
[Serializable]
public class SerializableClass { /* ... */ }
它的使用:
using System;
[Serializable]
public class MyClass
{
public int Id { get; set; }
public string Name { get; set; }
public MyClass(int id, string name)
{
Id = id;
Name = name;
}
}
在上述示例中,MyClass
类被标记为可序列化,这意味着该类的对象可以被序列化和反序列化。通常情况下,如果你想要将一个类的对象序列化(例如保存到文件或通过网络发送),你需要确保该类及其所有嵌套对象都是可序列化的,否则会抛出序列化异常。
指定条件编译提醒:
[Conditional]
: 用于指定条件编译。
[Conditional("DEBUG")]
public void DebugMethod() { /* ... */ }
条件编译特性的使用:
#define DEBUG
using System;
using System.Diagnostics;
public class Myclass
{
[Conditional("DEBUG")]
public static void Message(string msg)
{
Console.WriteLine(msg);
}
}
class Test
{
static void function1()
{
Myclass.Message("In Function 1.");
function2();
}
static void function2()
{
Myclass.Message("In Function 2.");
}
public static void Main()
{
Myclass.Message("In Main function.");
function1();
Console.ReadKey();
}
}
自定义特性
自定义特性的创建
自己定一个特性由于给你想标注的实体:类或者方法。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class MyCustomAttribute : Attribute
{
public string Description { get; set; }
public MyCustomAttribute(string description)
{
Description = description;
}
}
[AttributeUsage(...)]
: 这是 AttributeUsageAttribute 的应用,它是用来指定自定义特性的使用方式的特性。
AttributeTargets.Class | AttributeTargets.Method
: 指定可以应用该特性的程序实体类型。在这里,它表示该特性可以应用到类和方法上。
AllowMultiple = true
: 指定是否允许在同一个程序实体上多次应用该特性。在这里,AllowMultiple = true
表示允许在同一个类或方法上多次应用MyCustomAttribute
。这样定义后,你就可以在类和方法上使用
MyCustomAttribute
,并且可以多次在同一个类或方法上应用它,因为AllowMultiple
设置为true
。
自定义特性的使用
[MyCustom("Description 1")]
[MyCustom("Description 2")]
public class MyClass
{
[MyCustom("Method 1")]
[MyCustom("Method 2")]
public void MyMethod() { /* ... */ }
}
属性的特性
应用于属性而非普通方法和类的特性。
默认取值特性
用于给出属性的默认值。
public class MyClass
{
[DefaultValue(42)]
public int MyProperty { get; set; }
}
反射的定义
个人理解:指程序可以访问、检测和修改它本身状态或行为的一种能力。
反射的用处
反射(Reflection)有下列用途:
- 它允许在运行时查看特性(attribute)信息。
- 它允许审查集合中的各种类型,以及实例化这些类型。
- 它允许延迟绑定的方法和属性(property)。
- 它允许在运行时创建新类型,然后使用这些类型执行一些任务。
反射的使用
查看元数据
using System;
[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute
{
public readonly string Url;
public string Topic // Topic 是一个命名(named)参数
{
get
{
return topic;
}
set
{
topic = value;
}
}
public HelpAttribute(string url) // url 是一个定位(positional)参数
{
this.Url = url;
}
private string topic;
}
[HelpAttribute("Information on the class MyClass")]
class MyClass
{
}
namespace AttributeAppl
{
class Program
{
static void Main(string[] args)
{
System.Reflection.MemberInfo info = typeof(MyClass);
object[] attributes = info.GetCustomAttributes(true);
for (int i = 0; i < attributes.Length; i++)
{
System.Console.WriteLine(attributes[i]);
}
Console.ReadKey();
}
}
}
这段代码演示了使用我们新建的自定义特性修饰myclass之后使用反射提取特性的类别。
输出元数据:
HelpAttribute helpinfo = (HelpAttribute)attributes[i];
if (null != helpinfo)
{
System.Console.WriteLine("Url: " + helpinfo.Url);
System.Console.WriteLine("Topic: " + helpinfo.Topic);
}
注意看图如果不使用类型转换是没法直接输出Url的。