C# DotNetCore AOP简单实现

发布时间:2023年12月18日

背景

实际开发中业务和日志尽量不要相互干扰嵌套,否则很难维护和调试。

示例

using System.Reflection;

namespace CSharpLearn
{
    internal class Program
    {
        static void Main()
        {

            int age = 25;
            string name = "bingling";
            Person person = new(age, name);

            Console.WriteLine("====================不使用AOP====================");
            person.DisplayMessage();
            Console.WriteLine();
            person.DisplayMessage("name");

            Console.WriteLine("====================不使用AOP====================");
            Console.WriteLine();

            /*============================代理对象============================*/
            PersonProxyDynamic<Person> personProxyDynamic = new();
            personProxyDynamic.Before += (methodInfo) =>
            {
                List<string> pt = new();
                foreach (ParameterInfo? parameterInfo in methodInfo.GetParameters())
                {
                    if (parameterInfo.ParameterType.FullName != null)
                    {
                        pt.Add(parameterInfo.ParameterType.FullName);
                    }
                }
                Console.WriteLine($"准备执行{methodInfo.Name}({string.Join(",", pt)})");
            };
            personProxyDynamic.After += (methodInfo) =>
            {
                Console.WriteLine($"执行{methodInfo.Name}完毕");
            };

            /*============================代理对象============================*/

            Console.WriteLine("====================使用了AOP====================");
            personProxyDynamic.Excute(person, "DisplayMessage", new object[] { "name" });
            Console.WriteLine();

            personProxyDynamic.Excute(person, "DisplayMessage", null);
            Console.WriteLine();


            personProxyDynamic.Excute(person, "DisplayMessage", new object[] { 123 });
            Console.WriteLine();
            Console.WriteLine("====================使用了AOP====================");
        }
    }

    /// <summary>
    /// 人物类
    /// </summary>
    public class Person
    {
        /// <summary>
        /// 姓名
        /// </summary>
        private readonly string name;

        /// <summary>
        /// 年龄
        /// </summary>
        private readonly int age;

        public Person(int age, string name)
        {
            this.age = age;
            this.name = name;
        }

        /// <summary>
        /// 打印姓名和年龄
        /// </summary>
        public void DisplayMessage()
        {
            Console.WriteLine($"{{'age':{age},'name':'{name}'}}");
        }

        /// <summary>
        /// 根据需要打印姓名或年龄
        /// </summary>
        /// <param name="type">传入name或age</param>
        public void DisplayMessage(string type)
        {
            switch (type)
            {
                case "name":
                    Console.WriteLine($"{{'name':'{name}'}}");
                    break;
                case "age":
                    Console.WriteLine($"{{'age':'{age}'}}");
                    break;
            }
        }
    }

    /// <summary>
    /// 代理类
    /// </summary>
    /// <typeparam name="T">泛型T</typeparam>
    public class PersonProxyDynamic<T>
    {
        /// <summary>
        /// 执行方法前
        /// </summary>
        public Action<MethodInfo>? Before { get; set; }

        /// <summary>
        /// 执行方法后
        /// </summary>
        public Action<MethodInfo>? After { set; get; }

        /// <summary>
        /// 代理执行某个对象的某个方法
        /// </summary>
        /// <param name="t">被代理的对象</param>
        /// <param name="method">被执行的方法</param>
        /// <param name="args">被执行方法的参数列表</param>
        public void Excute(T t, string method, params object[]? args)
        {
            //获取被代理对象的所有名字为传入method的方法
            MethodInfo[]? methodInfos = typeof(T).GetMethods().Where(item => item.Name == method).ToArray();
            //没有此名字的方法
            if (methodInfos == null || methodInfos.Length == 0 || methodInfos.FirstOrDefault(item => item == null) != null)
            {
                Console.WriteLine($"{t}对象没有{method}方法");
                return;
            }
            //存在此名字的方法,注意区分是否为重载的方法
            foreach (MethodInfo methodInfo in methodInfos)
            {
                //方法传参列表是否和args每个元素的类型一一对应
                bool flag = true;
                //无参方法,传入null或长度为0的参数列表都可以
                if (methodInfo.GetParameters().Length == 0 && (args == null || args.Length == 0))
                {

                }
                //有参方法,两者传参长度需要一致、且传入的参数类型等于方法的参数类型或者隶属于其子类
                else if (methodInfo.GetParameters().Length == args?.Length)
                {
                    for (int i = 0; i < methodInfo.GetParameters().Length; i++)
                    {
                        Type type1 = methodInfo.GetParameters()[i].ParameterType;
                        Type type2 = args[i].GetType();
                        //参数列表类型不一致,且传入的参数类型不隶属于签名的参数类型
                        if (type1 != type2 && !type2.IsSubclassOf(type1))
                        {
                            flag = false;
                            break;
                        }
                    }
                }
                //有参方法,长度不一致
                else
                {
                    flag = false;
                }

                //命中用户想调用的方法
                if (flag)
                {
                    Before?.Invoke(methodInfo);
                    methodInfo.Invoke(t, args);
                    After?.Invoke(methodInfo);
                    return;
                }

            }

            Console.WriteLine("未找到您要调用的方法");
        }
    }
}

?运行结果

解析

业务中有一个Person类,其业务为调用Person实例的DisplayMessage方法打印该person对象的个人信息。

PersonProxyDynamic类为其动态代理类,我们在给其对象添加前置后置处理函数后,即可对person对象的所有方法进行代理,这样我们就可以在原本使用person对象方法的地方,替换成动态代理类的Execute方法,保证的原有的person代码不变,业务逻辑干净纯粹。

此示例仅供参考,由于使用了反射,生产环境若是对性能具备高要求,切勿轻易使用!!!

文章来源:https://blog.csdn.net/qq_36694133/article/details/135051486
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。