当前位置: 首页 > article >正文

NET Core的AOP实施方法1 DispatchProxy

NET Core的AOP实施方法1 DispatchProxy
NET Framework的AOP实施方法1 ContextBoundObject
NET Framework的AOP实施方法2 RealProxy

源码见Github

DispatchProxy

NET Core
DispatchProxy 是一个在 .NET 框架中引入的概念,特别是在 C# 语言中。它是一种特殊类型的代理,用于在运行时动态地分派方法调用到不同的实现。DispatchProxy 类位于 System.Runtime.Remoting.Proxies 命名空间中,并且是 RealProxy 类的一个派生类。

以下是 DispatchProxy 的一些关键点:

动态分派:DispatchProxy 允许开发者在运行时决定将方法调用分派给哪个对象。这使得可以在不修改现有代码的情况下,动态地改变对象的行为。

透明代理:DispatchProxy 是一种透明代理,这意味着客户端代码不需要知道代理的存在。客户端代码可以直接调用方法,就像它们直接调用实际对象一样。

类型安全:尽管 DispatchProxy 是动态分派的,但它仍然保持类型安全。代理对象可以被强制转换为任何接口类型,并且只有那些接口上的方法调用才会被分派。

创建自定义代理:开发者可以通过继承 DispatchProxy 类并重写 Invoke 方法来创建自己的代理。在 Invoke 方法中,开发者可以决定如何分派方法调用,例如,基于调用的方法名、参数或其他逻辑。

性能开销:由于 DispatchProxy 涉及到运行时的动态分派,因此可能会有一些性能开销。因此,它更适合于那些性能不是主要关注点的场景。

用途:DispatchProxy 可以用于多种场景,包括但不限于日志记录、性能监控、事务管理、安全性检查、Mock对象的创建等。

相较于RealProxy和ContextBoundObject,DispatchProxy的实现更加便捷

创建日志拦截器

public class LoggingDecorator<T> : DispatchProxy
{
    private T _decorated;

    protected override object Invoke(MethodInfo methodInfo, object[] args)
    {
        try
        {
            LogBefore(methodInfo, args);

            var result = methodInfo.Invoke(_decorated, args);
            if (methodInfo.IsAsyncMethod())
            {
                if (methodInfo.ReturnType == typeof(Task))
                {
                    var task = (Task)result;
                    var val = InternalAsyncHelper.AwaitTaskWithPostActionAndFinally(
                        task,
                        async () =>
                        {
                            Debug.WriteLine($"Task {methodInfo.Name} completed");
                        }, /*成功时执行*/
                        ex =>
                        {
                            if (ex != null)
                            {
                                Debug.WriteLine(
                                    $"Task {methodInfo.Name} threw an exception: {ex.ToString()}"
                                );
                            }
                        }
                    );
                    return val;
                }
                else
                {
                    var returnTypeGenericTypeArgument = methodInfo.ReturnType.GenericTypeArguments[
                        0
                    ];
                    var val = InternalAsyncHelper.CallAwaitTaskWithPostActionAndFinallyAndGetResult(
                        returnTypeGenericTypeArgument,
                        result,
                        async (o) =>
                        {
                            Debug.WriteLine($"Task {methodInfo.Name} completed with result {o}");
                        }, /*成功时执行*/
                        ex =>
                        {
                            if (ex != null)
                            {
                                Debug.WriteLine(
                                    $"Task {methodInfo.Name} threw an exception: {ex.ToString()}"
                                );
                            }
                        }
                    );
                    return val;
                }
            }
            else
            {
                LogAfter(methodInfo, args, result);
            }

            return result;
        }
        catch (Exception ex) when (ex is TargetInvocationException)
        {
            LogException(ex.InnerException ?? ex, methodInfo);
            throw ex.InnerException ?? ex;
        }
    }

    public static T Create(T decorated)
    {
        object proxy = Create<T, LoggingDecorator<T>>();
        ((LoggingDecorator<T>)proxy).SetParameters(decorated);

        return (T)proxy;
    }

    private void SetParameters(T decorated)
    {
        if (decorated == null)
        {
            throw new ArgumentNullException(nameof(decorated));
        }
        _decorated = decorated;
    }

    private void LogException(Exception exception, MethodInfo methodInfo = null)
    {
        Console.WriteLine(
            $"Class {_decorated.GetType().FullName}, Method {methodInfo.Name} threw exception:\n{exception}"
        );
    }

    private void LogAfter(MethodInfo methodInfo, object[] args, object result)
    {
        Console.WriteLine(
            $"Class {_decorated.GetType().FullName}, Method {methodInfo.Name} executed, Output: {result}"
        );
    }

    private void LogBefore(MethodInfo methodInfo, object[] args)
    {
        Console.WriteLine(
            $"Class {_decorated.GetType().FullName}, Method {methodInfo.Name} is executing"
        );
    }
}

代理异步的帮助类

internal static class InternalAsyncHelper
{
    public static bool IsAsyncMethod(this MethodInfo method)
    {
        return method.ReturnType == typeof(Task)
               || method.ReturnType.IsGenericType
               && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>);
    }

    public static async Task AwaitTaskWithPostActionAndFinally(
        Task actualReturnValue,
        Func<Task> postAction,
        Action<Exception> finalAction
    )
    {
        Exception exception = null;

        try
        {
            await actualReturnValue;
            await postAction();
        }
        catch (Exception ex)
        {
            exception = ex;
        }
        finally
        {
            finalAction(exception);
        }
    }

    public static async Task<T> AwaitTaskWithPostActionAndFinallyAndGetResult<T>(
        Task<T> actualReturnValue,
        Func<object, Task> postAction,
        Action<Exception> finalAction
    )
    {
        Exception exception = null;
        try
        {
            var result = await actualReturnValue;
            await postAction(result);
            return result;
        }
        catch (Exception ex)
        {
            exception = ex;
            throw;
        }
        finally
        {
            finalAction(exception);
        }
    }

    public static object CallAwaitTaskWithPostActionAndFinallyAndGetResult(
        Type taskReturnType,
        object actualReturnValue,
        Func<object, Task> action,
        Action<Exception> finalAction
    )
    {
        //AwaitTaskWithPostActionAndFinallyAndGetResult<taskReturnType>(actualReturnValue, action, finalAction);
        return typeof(InternalAsyncHelper)
            .GetMethod(
                "AwaitTaskWithPostActionAndFinallyAndGetResult",
                BindingFlags.Public | BindingFlags.Static
            )
            .MakeGenericMethod(taskReturnType)
            .Invoke(null, new object[] { actualReturnValue, action, finalAction });
    }
}

声明及调用示例

public interface ICalculator
{
    int Add(int a, int b);
    
    Task<int> AddAsync(int a, int b);
}
public class Calculator : ICalculator
{
    public int Add(int a, int b)
    {
        //throw new NotImplementedException("This method is not implemented. sorry!");
        return a + b;
    }

    public async Task<int> AddAsync(int a, int b)
    {
        await Task.Delay(1000);
        return a + b;
    }
}

示例

var decoratedCalculator = LoggingDecorator<ICalculator>.Create(new Calculator());
decoratedCalculator.Add(3, 5);
Console.WriteLine($"Started at {DateTime.Now:HH:mm:ss.fff}");
var res =decoratedCalculator.AddAsync(2, 4);

Console.WriteLine("Waiting for 1 seconds for querying customer...");
Console.WriteLine($"Querying {DateTime.Now:HH:mm:ss.fff}");
Console.WriteLine(res.GetAwaiter().GetResult());
Console.WriteLine($"Finished at {DateTime.Now:HH:mm:ss.fff}");

http://www.kler.cn/a/375297.html

相关文章:

  • RabbitMQ 存储机制
  • AI 原生时代,更要上云:百度智能云云原生创新实践
  • 图传推流学习(敬请期待)
  • C语言——八股文(笔试面试题)
  • Spring Cloud OpenFeign:基于Ribbon和Hystrix的声明式服务调用
  • LC:贪心题解
  • SAP(PP生产制造)拆解工单业务处理
  • YOLO11改进 | 卷积模块 | 提高网络的灵活性和表征能力的动态卷积【附代码+小白可上手】
  • 基于NVIDIA NIM平台实现盲人过马路的demo(一)
  • LeetCode516:最长回文子序列
  • 从0到1,用Rust轻松制作电子书
  • OpenWrt下安装Mosquitto
  • 在Java中 try catch 会影响性能吗?
  • 轻松部署自己的AI聊天助手LocalGPT并实现无公网IP远程交互
  • 包子凑数(完全背包)
  • 详解进制转换
  • windows@命令行中获取环境变量取值不展开取值(原值)
  • 大数据新视界 -- 大数据大厂都在用的数据目录管理秘籍大揭秘,附海量代码和案例
  • 青少年编程与数学 02-003 Go语言网络编程 03课题、网络编程协议
  • 代码随想录训练营Day09 | 150. 逆波兰表达式求值 - 239. 滑动窗口最大值 - 347.前 K 个高频元素
  • 从服务运营的阶段,进入到了精细化管理和智慧化运营的阶段的明厨亮早年开源了
  • ubuntu知识点滴积累
  • AI-基本概念-向量、矩阵、张量
  • 后台管理系统的通用权限解决方案(七)SpringBoot整合SpringEvent实现操作日志记录(基于注解和切面实现)
  • 学习虚幻C++开发日志——基础案例(持续更新中)
  • SpringSecurity框架(入门)