面向方面编程(Aspect-Oriented Programming,简称AOP)是一种编程范式,它通过分离横切关注点(如日志记录、事务管理、安全等)来提高代码的可维护性。AOP可以帮助我们将这些分散在各个模块中的横切关注点集中管理。本文将介绍如何使用C#中的特性(Attribute)来实现一个简单的AOP功能。
什么是特性?
C#特性(Attributes)允许你为代码中的各种元素(如类、方法、属性等)添加额外的数据。使用特性,你可以在声明这些元素时为它们添加元数据,这些元数据可以在运行时通过反射(Reflection)来访问和处理。
实现步骤
我们将通过以下几个步骤实现AOP:
- 创建一个自定义特性(Attribute)。
 - 使用反射(Reflection)机制读取特性。
 - 在方法执行前或后添加横切关注的逻辑(如日志记录)。
 
代码示例
第一步:创建一个自定义特性
首先,我们需要定义一个特性(Attribute)类。我们将创建一个名为 LogAttribute 的特性类,用于标记需要记录日志的方法。
using System;
[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public class LogAttribute : Attribute
{
    // 其它业务
}
第二步:使用特性标记方法
接下来,在需要启用日志记录功能的方法上应用这个特性。
public class MyService
{
    [Log]
    public void Work()
    {
        Console.WriteLine("Doing work...");
    }
    [Log]
    public void Study()
    {
        Console.WriteLine("Doing study...");
    }
}
第三步:创建AOP逻辑
我们需要创建一个代理类(Proxy)来在方法执行前后添加日志记录逻辑。为了简化示例,我们将使用反射(Reflection)来动态调用标记了 LogAttribute 的方法。
public class LogProxy
{
    private readonly object _target;
    public LogProxy(object target)
    {
        _target = target;
    }
    public void Invoke(string methodName)
    {
        MethodInfo method = _target.GetType().GetMethod(methodName);
        if (method != null && method.GetCustomAttribute(typeof(LogAttribute)) != null)
        {
            Console.WriteLine($"[Log] Method {methodName} 进入");
            method.Invoke(_target, null);
            Console.WriteLine($"[Log] Method {methodName} 完成");
        }
        else if (method != null)
        {
            method.Invoke(_target, null);
        }
        else
        {
            throw new ArgumentException("Method not found", nameof(methodName));
        }
    }
}
第四步:使用代理类
现在,我们可以使用 LogProxy 来调用标记了 LogAttribute 的方法,并在执行前后记录日志。
public class Program
{
    public static void Main(string[] args)
    {
        MyService service = new MyService();
        LogProxy proxy = new LogProxy(service);
        // 调用有日志记录的方法
        proxy.Invoke("Work");
        
        proxy.Invoke("Study");
        
        // 若调用不存在的方法,会抛出异常
        // proxy.Invoke("NonExistentMethod");
    }
}
运行结果
运行上述代码时,你将看到如下输出:
小结
通过本文,我们展示了如何从零开始使用C#中的特性(Attribute)来实现一个简单的AOP功能。我们创建了一个自定义特性类 LogAttribute,并通过代理类 LogProxy 使用反射在方法执行前后添加日志记录的逻辑。尽管这个示例相当简单,但它提供了一个实现AOP的基本框架,你可以根据实际需求对其进行扩展和优化。
希望这篇文章对你理解和应用AOP有所帮助!
