C# 特性(Attributes)是用于在运行时为程序元素(如类、方法、属性等)添加声明性信息的一种方式。这些信息可以在程序运行时通过反射(Reflection)访问。特性可以用来控制程序行为、添加元数据或者影响程序的运行时行为。
特性的基本要素
- 声明性信息:特性提供了一种方式在不改变代码逻辑的情况下向程序元素添加信息。
- 反射:通过反射机制可以在运行时查询和获取特性信息。
- 自定义特性:除了使用.NET提供的标准特性外,你还可以定义自己的特性。
示例代码
以下是一个定义和使用自定义特性的示例:
using System;// 定义一个简单的自定义特性
public class InfoAttribute : Attribute
{public string Description { get; set; }
}// 应用自定义特性到类上
[Info(Description = "This is a class for demonstration.")]
public class DemoClass
{// 应用自定义特性到方法上[Info(Description = "This method does nothing.")]public void DemoMethod(){}
}// 使用反射来读取特性信息
public class Program
{public static void Main(){// 获取类的特性信息InfoAttribute classAttribute = (InfoAttribute)Attribute.GetCustomAttribute(typeof(DemoClass), typeof(InfoAttribute));Console.WriteLine("Class Description: " + classAttribute.Description);// 获取方法的特性信息var method = typeof(DemoClass).GetMethod("DemoMethod");InfoAttribute methodAttribute = (InfoAttribute)Attribute.GetCustomAttribute(method, typeof(InfoAttribute));Console.WriteLine("Method Description: " + methodAttribute.Description);}
}
在这个例子中,InfoAttribute
是一个自定义特性类,它继承自 System.Attribute
。它有一个名为 Description
的公共属性。DemoClass
和它的方法 DemoMethod
被这个特性标记,并包含描述信息。在 Main
方法中,使用反射来获取这些描述信息并打印出来。这展示了如何定义特性、将它们应用到程序元素上,并在运行时检索它们的信息。
C# 特性Attribute除了用于添加元数据和通过反射检索信息之外,它们还可用于以下目的:
-
控制程序行为:
- 编译器指令:特性可以用来给编译器提供指令,如
[Obsolete]
用于标记过时的代码元素。 - 条件编译:特性可用于条件编译,例如
[Conditional("DEBUG")]
可以使方法仅在 DEBUG 模式下编译和执行。
- 编译器指令:特性可以用来给编译器提供指令,如
-
数据验证:
- 在数据模型中,特性经常用于验证数据。例如,在实体框架(Entity Framework)或数据注释(Data Annotations)中,你可以使用
[Required]
,[StringLength]
等特性来定义数据验证规则。
- 在数据模型中,特性经常用于验证数据。例如,在实体框架(Entity Framework)或数据注释(Data Annotations)中,你可以使用
-
序列化和反序列化控制:
- 在数据序列化过程中,特性用于控制如何将对象转换为 XML 或 JSON 等格式。例如,
[Serializable]
、[DataContract]
和[DataMember]
。
- 在数据序列化过程中,特性用于控制如何将对象转换为 XML 或 JSON 等格式。例如,
-
拦截器和动态代理:
- 在面向切面编程(AOP)中,特性用于定义方法拦截器。这在动态代理创建时特别有用,例如在 .NET Core 中的依赖注入(DI)。
-
声明性安全:
- 特性可用于定义安全要求,如
[PrincipalPermission]
用于声明方法执行所需的安全上下文。
- 特性可用于定义安全要求,如
-
编写插件和扩展:
- 在插件架构中,特性可用于标识插件类或方法,便于动态加载和识别。
-
单元测试框架:
- 在单元测试中,特性用于标记测试方法和测试类(例如
[TestMethod]
或[TestClass]
),以及进行测试设置和清理(如[TestInitialize]
和[TestCleanup]
)。
- 在单元测试中,特性用于标记测试方法和测试类(例如
-
依赖注入配置:
- 在依赖注入(DI)中,特性可以用于标记构造函数、属性或方法,以指导 DI 容器如何进行注入。
-
框架和库集成:
- 许多框架和库使用特性来集成与特定框架或库的功能,如 ASP.NET Core 中的路由、授权和过滤器特性(如
[Route]
,[Authorize]
,[ActionFilter]
等)。
- 许多框架和库使用特性来集成与特定框架或库的功能,如 ASP.NET Core 中的路由、授权和过滤器特性(如
通过这些用途,C# 特性成为了一种强大的机制,可以在不改变代码本身逻辑的情况下丰富和扩展代码的功能。
代码如下:
1. 编译器指令([Obsolete]
特性)
public class MyClass
{[Obsolete("Use NewMethod instead", false)] // 标记为过时public void OldMethod(){Console.WriteLine("This is the old method.");}public void NewMethod(){Console.WriteLine("This is the new method.");}
}
2. 数据验证(使用数据注释)
using System.ComponentModel.DataAnnotations;public class User
{[Required]public string Name { get; set; }[StringLength(10, ErrorMessage = "ID cannot be longer than 10 characters.")]public string ID { get; set; }
}
3. 序列化和反序列化控制([Serializable]
和 [DataMember]
特性)
using System.Runtime.Serialization;[Serializable]
public class Person
{public string Name { get; set; }[DataMember]public int Age { get; set; }
}
4. 面向切面编程(AOP)中的方法拦截器
public class LoggingAttribute : Attribute
{// 这里只是示例,实际的拦截实现需要结合拦截器框架使用public void BeforeCall() => Console.WriteLine("Before method call");public void AfterCall() => Console.WriteLine("After method call");
}public class MyClass
{[Logging]public void MyMethod(){Console.WriteLine("Executing the method.");}
}
5. 声明性安全
using System.Security.Permissions;public class SecureClass
{[PrincipalPermission(SecurityAction.Demand, Role = "Administrator")]public void SecureMethod(){Console.WriteLine("This method requires the Administrator role.");}
}
6. 插件和扩展标识
public class PluginAttribute : Attribute
{public string Name { get; set; }
}[Plugin(Name = "MyPlugin")]
public class MyPlugin
{// 插件的实现
}
7. 单元测试
using Microsoft.VisualStudio.TestTools.UnitTesting;[TestClass]
public class MyTestClass
{[TestMethod]public void MyTestMethod(){// 测试代码}
}
8. 依赖注入配置
public class MyService
{[Inject]public IDependency MyDependency { get; set; }// 假设 Inject 是一个标记依赖注入的特性
}
9. 框架和库集成
using Microsoft.AspNetCore.Mvc;public class MyController : Controller
{[Route("api/myroute")]public IActionResult MyAction(){return Ok();}
}
以上代码示例涵盖了特性在 C# 中的各种不同用途,展示了特性如何被应用于实际编程场景中。