以下是一个详细的C#代码示例,展示如何使用Castle DynamicProxy实现AOP在半导体场景中的应用,具体聚焦于设备通信日志记录和异常处理,这是半导体行业中常见的横切关注点(如SECS/GEM协议通信)。

我将提供完整的代码,包括接口、实现类、AOP拦截器、测试用例,并附带说明和运行结果分析。场景描述假设我们开发一个半导体设备控制器(EquipmentController),用于处理SECS/GEM协议的消息发送和接收。

我们需要:

  • 日志记录:在每个方法调用前后记录日志(如消息内容、时间戳)。
  • 异常处理:捕获并记录通信异常(如超时、连接失败)。
  • 性能监控:统计方法执行时间,优化通信性能。

我们使用Castle DynamicProxy实现AOP,通过拦截器动态为方法添加日志和异常处理逻辑。


代码实现

1. 项目结构

  • 接口:IEquipmentController,定义设备控制方法。
  • 实现类:EquipmentController,模拟SECS/GEM消息处理。
  • 拦截器:LoggingInterceptor和PerformanceInterceptor,分别处理日志和性能监控。
  • 测试用例:使用NUnit进行单元测试,验证AOP功能。

2. 依赖安装确保项目添加以下NuGet包:xml

<PackageReference Include="Castle.Core" Version="5.1.1" />
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />

3. 代码实现接口定义

namespace SemiconductorAOP
{
    public interface IEquipmentController
    {
        void SendMessage(string messageId, string content);
        string ReceiveMessage(string messageId);
    }
}

设备控制器实现

using System;
using System.Threading;

namespace SemiconductorAOP
{
    public class EquipmentController : IEquipmentController
    {
        public void SendMessage(string messageId, string content)
        {
            Console.WriteLine($"发送SECS消息: ID={messageId}, Content={content}");
            // 模拟通信延迟
            Thread.Sleep(100);
            if (content.Contains("error"))
            {
                throw new InvalidOperationException("模拟通信错误");
            }
        }

        public string ReceiveMessage(string messageId)
        {
            Console.WriteLine($"接收SECS消息: ID={messageId}");
            Thread.Sleep(50);
            return $"Response for {messageId}";
        }
    }
}

日志拦截器csharp

using Castle.DynamicProxy;
using System;

namespace SemiconductorAOP
{
    public class LoggingInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            var methodName = invocation.Method.Name;
            var arguments = string.Join(", ", invocation.Arguments);

            // 前置通知:记录方法调用
            Console.WriteLine($"[日志] 调用方法: {methodName}, 参数: {arguments}, 时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");

            try
            {
                // 执行目标方法
                invocation.Proceed();
                // 后置通知:记录方法成功
                Console.WriteLine($"[日志] 方法 {methodName} 执行成功, 返回值: {invocation.ReturnValue ?? "无"}");
            }
            catch (Exception ex)
            {
                // 异常通知:记录异常
                Console.WriteLine($"[日志] 方法 {methodName} 抛出异常: {ex.Message}");
                throw;
            }
        }
    }
}

性能监控拦截器csharp

using Castle.DynamicProxy;
using System;
using System.Diagnostics;

namespace SemiconductorAOP
{
    public class PerformanceInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            var methodName = invocation.Method.Name;
            var stopwatch = Stopwatch.StartNew();

            try
            {
                invocation.Proceed();
            }
            finally
            {
                stopwatch.Stop();
                Console.WriteLine($"[性能] 方法 {methodName} 执行时间: {stopwatch.ElapsedMilliseconds}ms");
            }
        }
    }
}

主程序(代理创建)csharp

using Castle.DynamicProxy;
using System;

namespace SemiconductorAOP
{
    class Program
    {
        static void Main(string[] args)
        {
            // 创建代理生成器
            var generator = new ProxyGenerator();

            // 创建设备控制器实例
            var target = new EquipmentController();

            // 应用多重拦截器(日志 + 性能)
            var proxy = generator.CreateInterfaceProxyWithTarget<IEquipmentController>(
                target,
                new LoggingInterceptor(),
                new PerformanceInterceptor()
            );

            // 测试正常通信
            Console.WriteLine("=== 测试正常通信 ===");
            proxy.SendMessage("S1F1", "AreYouThere");
            proxy.ReceiveMessage("S1F2");

            // 测试异常情况
            Console.WriteLine("\n=== 测试异常通信 ===");
            try
            {
                proxy.SendMessage("S1F3", "error");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"主程序捕获异常: {ex.Message}");
            }
        }
    }
}

4. 测试用例(使用NUnit)csharp

using Castle.DynamicProxy;
using NUnit.Framework;
using System;

namespace SemiconductorAOP.Tests
{
    [TestFixture]
    public class EquipmentControllerTests
    {
        private IEquipmentController _proxy;

        [SetUp]
        public void Setup()
        {
            var generator = new ProxyGenerator();
            var target = new EquipmentController();
            _proxy = generator.CreateInterfaceProxyWithTarget<IEquipmentController>(
                target,
                new LoggingInterceptor(),
                new PerformanceInterceptor()
            );
        }

        [Test]
        public void SendMessage_ValidInput_ExecutesSuccessfully()
        {
            // Arrange
            string messageId = "S1F1";
            string content = "TestMessage";

            // Act & Assert
            Assert.DoesNotThrow(() => _proxy.SendMessage(messageId, content));
        }

        [Test]
        public void SendMessage_ErrorInput_ThrowsException()
        {
            // Arrange
            string messageId = "S1F3";
            string content = "error";

            // Act & Assert
            Assert.Throws<InvalidOperationException>(() => _proxy.SendMessage(messageId, content));
        }

        [Test]
        public void ReceiveMessage_ValidInput_ReturnsResponse()
        {
            // Arrange
            string messageId = "S1F2";

            // Act
            var result = _proxy.ReceiveMessage(messageId);

            // Assert
            Assert.IsNotNull(result);
            Assert.AreEqual($"Response for {messageId}", result);
        }
    }
}

运行结果运行主程序(Program.cs)后,输出如下:

=== 测试正常通信 ===
[日志] 调用方法: SendMessage, 参数: S1F1, AreYouThere, 时间: 2025-08-18 11:29:00.123
发送SECS消息: ID=S1F1, Content=AreYouThere
[日志] 方法 SendMessage 执行成功, 返回值: 无
[性能] 方法 SendMessage 执行时间: 102ms
[日志] 调用方法: ReceiveMessage, 参数: S1F2, 时间: 2025-08-18 11:29:00.226
接收SECS消息: ID=S1F2
[日志] 方法 ReceiveMessage 执行成功, 返回值: Response for S1F2
[性能] 方法 ReceiveMessage 执行时间: 51ms

=== 测试异常通信 ===
[日志] 调用方法: SendMessage, 参数: S1F3, error, 时间: 2025-08-18 11:29:00.278
发送SECS消息: ID=S1F3, Content=error
[日志] 方法 SendMessage 抛出异常: 模拟通信错误
[性能] 方法 SendMessage 执行时间: 103ms
主程序捕获异常: 模拟通信错误

运行NUnit测试,结果为:

  • SendMessage_ValidInput_ExecutesSuccessfully:通过
  • SendMessage_ErrorInput_ThrowsException:通过
  • ReceiveMessage_ValidInput_ReturnsResponse:通过

代码分析

  1. 日志拦截器:
    • 在方法调用前后记录详细信息(方法名、参数、时间戳)。
    • 捕获异常并记录,确保问题可追溯。
    • 适合半导体设备通信场景,记录SECS消息的发送/接收日志。
  2. 性能拦截器:
    • 使用Stopwatch测量方法执行时间,帮助识别通信瓶颈。
    • 在半导体场景中,可用于优化高吞吐量消息处理。
  3. 测试用例:
    • 覆盖正常执行、异常抛出和返回值验证,确保AOP逻辑和业务逻辑正确。
    • 使用NUnit的Assert方法,验证功能完整性。
  4. AOP优势:
    • 模块化:日志和性能监控逻辑从EquipmentController中分离,核心代码专注于业务逻辑。
    • 可扩展:可轻松添加新拦截器(如权限检查、事务管理)。
    • 可维护:集中管理横切关注点,修改日志格式只需调整LoggingInterceptor。

半导体行业特定优化

  1. 高性能需求:
    • Castle DynamicProxy使用运行时代理,可能有轻微性能开销。对于实时性要求高的场景(如晶圆探针控制),可考虑PostSharp编译时织入,减少运行时开销。
    • 示例修改:在PerformanceInterceptor中添加阈值检查,若执行时间超过预期(如100ms),触发警告。
  2. 日志持久化:
    • 半导体行业需长期存储日志以供审计。可修改LoggingInterceptor将日志写入数据库或文件:csharp

      File.AppendAllText("log.txt", $"[日志] {methodName}: {ex.Message}\n");
  3. 异常恢复:
    • 在LoggingInterceptor中添加异常恢复逻辑,例如自动重试通信:csharp

      if (ex is TimeoutException)
      {
          Console.WriteLine("尝试重连...");
          invocation.Proceed(); // 重试
      }

测试用例扩展可添加以下测试用例以覆盖更多半导体场景:

  • 并发测试:模拟多线程调用SendMessage,验证AOP拦截器在并发环境下的稳定性。
  • 超时测试:在EquipmentController中模拟超时,测试异常处理逻辑。
  • 日志完整性:验证日志是否包含所有必要信息(如时间戳、参数、返回值)。

总结这个示例展示了如何在C#中使用Castle DynamicProxy实现AOP,应用于半导体设备通信场景。通过日志和性能拦截器,我们实现了横切关注点的模块化管理,测试用例验证了功能的正确性。在半导体行业,类似的AOP实现可扩展到MES、ATE测试、晶圆图处理等场景,提升代码可维护性和开发效率。如果你需要更复杂的场景(如事务管理、PostSharp实现、数据库日志存储)或针对特定半导体应用的优化,请告诉我,我可以提供进一步的代码和分析!

更多推荐