目录
C# 特性(Attribute)
规定特性(Attribute)
预定义特性(Attribute)
创建自定义特性(Attribute)
C# 反射(Reflection)
优缺点
反射(Reflection)的用途
使用反射访问特性
特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。
特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:预定义特性和自定义特性。
在 C# 中,规定特性(Attribute)的语法如下所示:
[attribute(positional_parameters, name_parameter = value, ...)]
element
element 可以是一个程序中的各种代码元素,如类、方法、属性等。特性会应用到这些代码元素上,为它们添加额外的元数据信息。
以下是一个示例,演示了一个特性的使用:
[Serializable]
public class MyClass
{
// 类定义
}
在这个示例中,Serializable 是一个特性,它被应用到 MyClass 类上,为这个类添加了序列化的能力。
另外,特性也可以带有参数,例如:
[Author("John Doe", Version = 2)]
public void SomeMethod()
{
// 方法定义
}
这里的 Author 特性带有一个位置参数和一个命名参数,它们提供了关于方法作者和版本信息的元数据。
.Net 框架提供了三种预定义特性:
1、AttributeUsage
AttributeUsage 特性用于指定自定义特性的使用方式。通过在自定义特性类上应用 AttributeUsage 特性,可以定义该特性可以应用到哪些程序元素上,以及是否允许多次应用同一个特性。
以下是一个关于 AttributeUsage 的简单示例:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,
AllowMultiple = true, Inherited = false)]
public class CustomAttribute : Attribute
{
// 自定义特性类的定义
}
[Custom]
public class MyClass
{
// 类定义
}
[Custom]
public void MyMethod()
{
// 方法定义
}
在这个示例中,AttributeUsage 特性被应用到 CustomAttribute 类上。它指定了该特性可以应用到类和方法上(通过 AttributeTargets.Class | AttributeTargets.Method 参数),允许多次应用同一个特性(AllowMultiple = true),并且不允许继承(Inherited = false)。
2、Conditional
Conditional 特性允许您将方法调用标记为条件方法调用。这意味着,带有 Conditional 特性的方法只有在定义了特定的预处理器符号时才会被调用。
下面是一个简单的示例:
#define DEBUG
public class MyClass
{
[Conditional("DEBUG")]
public void DebugMethod()
{
// 调试时执行的代码
}
public void SomeMethod()
{
DebugMethod(); // 只有在定义了 DEBUG 符号时才会被调用
}
}
在这个示例中,DebugMethod 方法带有 Conditional 特性,并且只有在定义了名为 DEBUG 的预处理器符号时才会被调用。
3、Obsolete
Obsolete 特性用于标记代码中已经过时的元素(如方法、属性等)。当程序中使用了被 Obsolete 标记的元素时,编译器会发出警告或错误信息,提示开发人员使用更新的替代方案。
以下是一个简单的示例:
public class MyClass
{
[Obsolete("This method is obsolete. Use NewMethod instead.")]
public void OldMethod()
{
// 过时的方法实现
}
public void NewMethod()
{
// 新方法的实现
}
}
在这个示例中,OldMethod 方法被标记为过时,当其他代码调用它时,会得到一条警告,提示开发者使用 NewMethod 方法代替。
.Net 框架允许创建自定义特性,用于存储声明性的信息,且可在运行时被检索。该信息根据设计标准和应用程序需要,可与任何目标元素相关。
创建并使用自定义特性包含四个步骤:
1、声明自定义特性
首先,你需要声明一个新的特性类。这个类应该继承自 System.Attribute 类。在这个类中,你可以添加自定义的属性和方法,以便存储和处理声明性的信息。以下是一个简单的示例:
using System;
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
public class CustomAttribute : Attribute
{
private string description;
public CustomAttribute(string description)
{
this.description = description;
}
public string Description
{
get { return description; }
}
}
2、构建自定义特性
在上面的示例中,我们创建了一个名为 CustomAttribute 的自定义特性类。该类具有一个带有描述信息参数的构造函数,并且具有一个名为 Description 的只读属性。
3、在目标程序元素上应用自定义特性
一旦你声明了自定义特性类,你就可以在目标程序元素(如类、方法等)上应用这个特性。例如,在一个类或方法的前面使用 [Custom("Some description")] 这样的语法来应用自定义特性。
4、通过反射访问特性
最后,你可以使用反射来访问应用在目标程序元素上的自定义特性,并检索其中存储的信息。通过反射,你可以在运行时获取和处理这些特性,以实现根据特性存储的信息来定制程序行为。
反射指程序可以访问、检测和修改它本身状态或行为的一种能力。
程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。
您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。
优点:
缺点:
查看特性信息: 通过反射,可以在运行时获取特性(attribute)的信息,包括类型、成员和程序集级别的特性。这使得我们可以根据特性来执行相应的逻辑,比如在自定义框架中根据特性来做权限检查或者其他元数据相关的操作。
审查集合中的各种类型: 反射允许我们在运行时检查程序集中的类型信息,包括类、方法、属性等。这对于编写一些通用的工具和框架非常有用,比如自动化测试框架、ORM(对象关系映射)工具等。
延迟绑定的方法和属性: 反射使得我们可以在运行时动态地调用方法和访问属性,这种灵活性在某些情况下非常有用,比如基于配置文件的应用程序或者插件系统。
创建新类型并执行任务: 反射能够在运行时动态地创建新类型的实例,并调用其方法,这对于一些需要动态生成类型的场景非常有用,比如基于配置的工厂模式、动态代理等。
总的来说,反射为C#提供了一种强大的机制,使得我们可以在运行时动态地探索和操作类型信息,为编写更加灵活和可扩展的程序提供了便利。但需要注意的是,反射也可能会带来性能上的开销,因此在使用时需要权衡利弊。
使用反射访问特性可以通过以下步骤实现:
1、获取类型的信息:使用Type.GetType或者typeof关键字来获取要访问特性的类型的Type对象。
Type type = typeof(MyClass);
2、获取特性的信息:使用GetCustomAttributes方法获取指定类型上的所有特性。该方法返回一个包含特性对象的数组。
object[] attributes = type.GetCustomAttributes(true);
3、遍历特性并获取信息:遍历特性对象数组,可以获取每个特性的属性值。
foreach (object attribute in attributes)
{
if (attribute is MyAttribute myAttribute)
{
// 访问特性的属性
string name = myAttribute.Name;
int age = myAttribute.Age;
// 执行特性的方法
myAttribute.DoSomething();
}
}
完整示例代码如下:
using System;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
class MyAttribute : Attribute
{
public string Name { get; set; }
public int Age { get; set; }
public void DoSomething()
{
Console.WriteLine("正在做某事。。。");
}
}
[My(Name = "John", Age = 30)]
class MyClass
{
// 类的定义
}
class Program
{
static void Main(string[] args)
{
Type type = typeof(MyClass);
object[] attributes = type.GetCustomAttributes(true);
foreach (object attribute in attributes)
{
if (attribute is MyAttribute myAttribute)
{
string name = myAttribute.Name;
int age = myAttribute.Age;
myAttribute.DoSomething();
}
}
}
}
在上述示例中,MyAttribute是一个自定义特性,应用于MyClass类。通过反射获取MyClass的类型信息后,遍历特性对象数组并访问特性的属性和方法。
注意,GetCustomAttributes方法的第一个参数可以指定是否包括继承的特性,默认为false。如果要获取继承的特性,可以将该参数设置为true。