C# 特性(Attribute)
在 .NET Core 的开发体系中,特性(Attribute)不仅仅是一个简单的标签,更是实现声明式编程、解耦业务逻辑与基础设施代码的核心机制。无论是数据验证、API 路由控制,还是复杂的面向切面编程(AOP),特性都提供了高效的解决方案。
1. 特性 Attribute
特性
从本质上讲,特性是一种将元数据(Metadata)附加到代码元素(如类、方法、属性、参数等)上的机制。它不会直接改变代码的执行逻辑,而是为编译器或运行时提供额外的描述性信息。
理解为给代码打的“标签”或“注解”。例如:
[Required]告诉框架该字段不能为空。[HttpGet]告诉 ASP.NET Core 该方法仅响应 GET 请求。[Serializable]告诉序列化器该对象可以被序列化。
在没有引入特性之前,开发者往往需要通过大量的if-else或switch语句来处理诸如数据库映射、JSON 序列化、数据验证等逻辑。这导致代码紧密耦合,维护困难。
引入特性后,实现了声明式编程的优势:
- 解耦:业务代码专注于核心逻辑,横切关注点(如日志、验证、权限)通过特性分离。
- 统一规则:框架通过扫描特性自动执行相应逻辑,确保行为一致。
- **简洁性无需编写繁琐的基础设施代码,只需添加标签即可生效。
2.自定义特性
虽然 .NET 提供了丰富的内置特性,但在实际开发中,我们常需要根据业务需求创建自定义特性例如实现特定的日志记录、权限校验或缓存策略。
创建自定义特性通常遵循以下步骤:
- 创建一个继承自
System.Attribute的类。 - 使用
AttributeUsage指定特性的适用目标(类、方法、属性等)。 - 定义构造函数和属性以传递参数。
自定义日志特性
需要一个特性,用于标记需要记录详细执行日志的方法。
using System; // 1. 定义特性类 [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] public class CustomLogAttribute : Attribute { public string Message { get; set; } public LogLevel Level { get; set; } = LogLevel.Information; public CustomLogAttribute(string message) { Message = message; } } public enum LogLevel { Information, Warning, Error }使用自定义特性
public class OrderService { // 2. 应用特性 [CustomLog("开始处理订单创建", Level = LogLevel.Information)] public void CreateOrder(Order order) { // 业务逻辑 Console.WriteLine($"Order {order.Id} created."); } }此时,CustomLogAttribute仅仅是一个元数据标记。若要使其真正生效(即执行日志记录逻辑),通常需要结合反射或AOP拦截器。
3.扩展 AOP 应用
特性本身不执行代码,必须配合拦截机制才能实现面向切面编程(AOP)。在 .NET Core 中,实现 AOP 的主流方式包括使用动态代理库(如 Castle DynamicProxy)或依赖注入容器的拦截扩展(如 Autofac)。
AOP 的核心思想
AOP旨在将横切关注点(如日志、事务、异常处理)从业务逻辑中剥离。当调用被特性标记的方法时,流程如下:
- 调用方触发方法。
- 代理对象拦截调用。
- 执行前置逻辑(如记录开始时间、检查权限)。
- 执行真实业务方法。
- 执行后置逻辑(如记录结束时间、捕获异常)。
结合 Castle DynamicProxy 实现日志拦截
以下示例展示如何通过实现 `IInterceptor接口,读取自定义特性并执行日志记录。
定义拦截器
using Castle.DynamicProxy; using System.Reflection; public class LogInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { // 1. 获取方法上的自定义特性 var method = invocation.MethodInvocationTarget; var logAttribute = method.GetCustomAttributes(typeof(CustomLogAttribute), true) .FirstOrDefault() as CustomLogAttribute; if (logAttribute != null) { // 2. 前置逻辑:记录开始 Console.WriteLine($"[LOG] {logAttribute.Message} - Start"); } try { // 3. 执行真实方法 invocation.Proceed(); } catch (Exception ex) { // 4. 异常处理 Console.WriteLine($"[ERROR] Exception occurred: {ex.Message}"); throw; } finally { if (logAttribute != null) { // 5. 后置逻辑:记录结束 Console.WriteLine($"[LOG] {logAttribute.Message} - End"); } } } }创建代理并执行
var proxyGenerator = new ProxyGenerator(); var interceptor = new LogInterceptor(); // 创建 OrderService 的代理对象 var orderService = proxyGenerator.CreateClassProxy<OrderService>(interceptor); var order = new Order { Id = 1001 }; orderService.CreateOrder(order); // 输出结果: // [LOG] 开始处理订单创建 - Start // Order 1001 created. // [LOG] 开始处理订单创建 - End- Autofac + Castle DynamicProxy:在 ASP.NET Core 项目中,常替换默认 DI 容器为 Autofac,利用其 EnableInterfaceInterceptors 或 EnableClassInterceptors 功能,自动为注册的服务生成代理,无需手动创建 ProxyGenerator。
- DispatchProxy:.NET Core 内置的轻量级代理类,适用于简单的场景,但功能不如 Castle DynamicProxy 强大。
4.常用内置特性分类
.NET Core 框架内置了大量特性,覆盖了 Web 开发、数据验证、依赖注入等多个领域。熟练掌握这些特性能极大提升开发效率。
API 与 MVC 控制
这些特性主要用于 ASP.NET Core Web API 和 MVC 控制器,定义路由、HTTP 方法和行为。
| 特性 | 说明 | 示例 |
|---|---|---|
[ApiController] | 标记控制器为 API 风格,启用自动模型验证和错误响应。 | [ApiController] |
[Route] | 定义路由模板。 | [Route("api/[controller]")] |
[HttpGet]/[HttpPost] | 指定允许的 HTTP 谓词。 | [HttpGet("{id}")] |
[FromBody] | 指示参数从请求正文中绑定。 | public IActionResult Post([FromBody] User user) |
[FromQuery] | 指示参数从查询字符串中绑定。 | public IActionResult Get([FromQuery] int page) |
数据验证特性
主要用于 DTO(数据传输对象)或实体模型,配合模型验证中间件使用。
| 特性 | 说明 | 示例 |
|---|---|---|
[Required] | 字段不能为 null 或空。 | [Required(ErrorMessage = "姓名必填")] |
[StringLength] | 限制字符串长度。 | [StringLength(100)] |
[Range] | 限制数值范围。 | [Range(1, 120)] |
[EmailAddress] | 验证邮箱格式。 | [EmailAddress] |
[RegularExpression] | 使用正则表达式验证。 | [RegularExpression(@"^\d+$")] |
数据实体特性 (Entity Framework Core)
用于配置数据库映射关系。
| 特性 | 说明 | 示例 |
|---|---|---|
[Key] | 指定主键。 | [Key] |
[Table] | 指定对应的数据库表名。 | [Table("Users")] |
[Column] | 指定列名或类型。 | [Column("user_name")] |
[NotMapped] | 排除属性,不映射到数据库。 | [NotMapped] |
[DatabaseGenerated] | 指定数据库生成策略(如自增)。 | [DatabaseGenerated(DatabaseGeneratedOption.Identity)] |
依赖注入与服务生命周期
引入了直接标记服务生命周期的特性,简化了注册过程。
| 特性 | 说明 |
|---|---|
[ServiceLifetime.Scoped] | 标记服务为 Scoped 生命周期。 |
[ServiceLifetime.Singleton] | 标记服务为 Singleton 生命周期。 |
[ServiceLifetime.Transient] | 标记服务为 Transient 生命周期。 |
PS:使用这些特性时,通常需要在程序启动时扫描程序集并自动注册服务。
安全与授权
| 特性 | 说明 |
|---|---|
[Authorize] | 要求用户经过身份验证才能访问。 |
[AllowAnonymous] | 允许匿名访问,通常用于覆盖全局授权策略。 |
[ValidateAntiForgeryToken] | 防止跨站请求伪造攻击。 |
总结
特性(Attribute)是 .NET Core 生态中连接元数据与运行时行为的桥梁。
- 理解本质:特性是元数据,需配合反射或拦截器才能产生实际效果。
- 自定义扩展:通过继承
Attribute类,可以轻松扩展业务所需的标记能力。 - AOP 实战:结合 Castle DynamicProxy 或 Autofac,利用特性实现日志、事务、权限等横切逻辑的自动化处理,显著提升代码的可维护性。
- 善用内置:熟练掌握系统内置的特性,能够以更少的代码实现标准化的 Web 开发、数据验证和 ORM 映射。