SourceGenerator 使用姿势(1):生成代理类,实现简单的AOP

SourceGenerator 已经出来很久了,也一直在关注。之前观摩大佬 SourceGenerator 使用姿势(1):生成代理类,实现简单的AOP xljiulangWebApiClient 使用 SourceGenerator 生成接口代理类,深受启发,准备拿过来用看看(发出白嫖的声音),写个编译期静态代理AOP。 本篇重点是怎么获取元数据,得到想要的数据,生成想要的代码(往下拖到第 4 点)。

几个月前写了个demo,现在趁着有空重新整理完善了下。.net 6 新增了个 IIncrementalGenerator 进行增量编译,这个还没研究,后面再说。

我的思路是 继承,生成一个类去继承需要拦截的实际类,然后重写相关的方法,此时插入额外的方法,比如 Before,After 等。这就要求相关方法必须是 可重写的, virtualoverride。好了,开干。

1、定义Aop属性,打个标签,SourceGenerator 根据这个标签查找相关的 class 或 interface

1     ///
 2     /// Aop 拦截器
 3     ///
 4     public interface IAopInterceptor
 5     {
 6         ///
 7         /// 执行前操作,同步方法调用
 8         ///
 9         ///
10         ///
11         AopContext Before(AopContext context);
12         ///
13         /// 执行前操作,异步方法调用
14         ///
15         ///
16         ///
17         ValueTask BeforeAsync(AopContext context);
18         ///
19         /// 执行后操作,同步方法调用
20         ///
21         ///
22         ///
23         AopContext After(AopContext context);
24         ///
25         /// 执行后操作,异步方法调用
26         ///
27         ///
28         ///
29         ValueTask AfterAsync(AopContext context);
30         ///
31         /// 执行方法,同步方法调用
32         ///
33         ///
34         ///
35         AopContext Next(AopContext context);
36         ///
37         /// 执行方法,异步方法调用
38         ///
39         ///
40         ///
41         ValueTask NextAsync(AopContext context);
42     }

可以不要 IAopInterceptor 这个接口,这里加了只是为了约束。

SourceGenerator 使用姿势(1):生成代理类,实现简单的AOPSourceGenerator 使用姿势(1):生成代理类,实现简单的AOP
1     public class AopInterceptor : Attribute, IAopInterceptor
 2     {
 3         ///
 4         /// 是否执行 Before
 5         ///
 6         public bool HasBefore { get; set; }
 7         ///
 8         /// 是否执行 After
 9         ///
10         public bool HasAfter { get; set; }
11         ///
12         /// 是否执行 Aop 的 Next
13         ///
14         public bool HasAopNext { get; set; }
15         ///
16         /// 是否执行实际的方法
17         ///
18         public bool HasActualNext { get; set; }
19
20         ///
21         /// 默认执行所以方法
22         ///
23         public AopInterceptor()
24         {
25             HasBefore = true;
26             HasAopNext = true;
27             HasActualNext = true;
28             HasAfter = true;
29         }
30
31         public virtual AopContext Before(AopContext context) => context;
32
33         public virtual async ValueTask BeforeAsync(AopContext context)
34         {
35             await ValueTask.CompletedTask;
36             return context;
37         }
38
39         public virtual AopContext After(AopContext context)
40         {
41             return context.Exception != null ? throw context.Exception : context;
42         }
43
44         public virtual async ValueTask AfterAsync(AopContext context)
45         {
46             if (context.Exception != null)
47                 throw context.Exception;
48
49             await ValueTask.CompletedTask;
50             return context;
51         }
52
53         public virtual AopContext Next(AopContext context)
54         {
55             try
56             {
57                 context.Invoke();
58             }
59             catch (Exception e)
60             {
61                 context.Exception = e;
62             }
63             return context;
64         }
65
66         public virtual async ValueTask NextAsync(AopContext context)
67         {
68             try
69             {
70                 context = await context.InvokeAsync();
71             }
72             catch (Exception e)
73             {
74                 context.Exception = e;
75             }
76
77             return context;
78         }
79     }

View Code

2、定义上下文,主要包含 是否是异步,是否有返回值,还有实际方法的委托。决定了调用实际方法的时候怎么调用

 1     ///
 2     /// Aop 上下文
 3     ///
 4     public struct AopContext
 5     {
 6         ///
 7         /// 是否是异步
 8         ///
 9         public bool IsTask { get; private set; }
10         ///
11         /// 是否有返回值
12         ///
13         public bool HasReturnValue { get; private set; }
14         ///
15         /// 方法输入参数
16         ///
17         public Dictionary<string, dynamic> MethodInputParam { get; private set; }
18
19         ///
20         /// 实际方法执行结果,可能是 Task
21         ///
22         public Func<dynamic> ActualMethod { get; set; }
23         ///
24         /// 返回值,具体的值
25         ///
26         public dynamic ReturnValue { get; set; }
27         ///
28         /// 异常信息
29         ///
30         public Exception Exception { get; set; }
31         ///
32         /// IServiceProvider
33         ///
34         public IServiceProvider ServiceProvider { get; private set; }
35
36         ///
37         /// 初始化
38         ///
39         ///
40         ///
41         ///
42         ///
43         ///
44         public AopContext(IServiceProvider serviceProvider, Dictionary<string, dynamic> methodInputParam, bool isTask, bool hasReturnValue, Func<dynamic> actualMethod) : this()
45         {
46             ServiceProvider = serviceProvider;
47             MethodInputParam = methodInputParam;
48             IsTask = isTask;
49             HasReturnValue = hasReturnValue;
50             ActualMethod = actualMethod;
51         }
52
53         ///
54         /// 执行实际方法 异步
55         ///
56         ///
57         public async ValueTask InvokeAsync()
58         {
59             if (ActualMethod == null)
60                 return this;
61
62             if (HasReturnValue)
63             {
64                 ReturnValue = await ActualMethod();
65                 return this;
66             }
67
68             await ActualMethod();
69             return this;
70         }
71
72         ///
73         /// 执行实际方法 同步
74         ///
75         ///
76         public void Invoke()
77         {
78             if (ActualMethod == null)
79                 return;
80
81             //特殊处理 同步且没有返回值,用 Task.Run 包装
82             if (!IsTask && !HasReturnValue)
83                 ActualMethod.Invoke().GetAwaiter().GetResult();
84             else
85                 ReturnValue = ActualMethod.Invoke();
86         }
87     }

3、硬编码实现类

3.1、定义拦截器

SourceGenerator 使用姿势(1):生成代理类,实现简单的AOPSourceGenerator 使用姿势(1):生成代理类,实现简单的AOP
1     ///
 2     /// 常规服务,执行所有方法
 3     ///
 4     public class SampleAttribute : AopInterceptor
 5     {
 6         /// 执行前操作,同步方法调用
 7         ///
 8         ///
 9         public override AopContext Before(AopContext context)
10         {
11             Console.WriteLine("Before...");
12             return base.Before(context);
13         }
14
15         /// 执行前操作,异步方法调用
16         ///
17         ///
18         public override ValueTask BeforeAsync(AopContext context)
19         {
20             Console.WriteLine("BeforeAsync...");
21             return base.BeforeAsync(context);
22         }
23
24         public override AopContext After(AopContext context)
25         {
26             Console.WriteLine("After...");
27             return context;
28         }
29
30         /// 执行后操作,异步方法调用
31         ///
32         ///
33         public override ValueTask AfterAsync(AopContext context)
34         {
35             Console.WriteLine("AfterAsync...");
36             return base.AfterAsync(context);
37         }
38
39         /// 执行方法,同步方法调用
40         ///
41         ///
42         public override AopContext Next(AopContext context)
43         {
44             Console.WriteLine("Next...");
45             return base.Next(context);
46         }
47
48         /// 执行方法,异步方法调用
49         ///
50         ///
51         public override ValueTask NextAsync(AopContext context)
52         {
53             Console.WriteLine("NextAsync...");
54             return base.NextAsync(context);
55         }
56     }

View Code

定义接口

1     public interface ITestService
2     {
3         [Sample]
4         DateTime SampleSync();
5
6         [Sample]
7         ValueTask SampleAsync();
8     }

3.2、定义实现类

1     public class TestService : ITestService
 2     {
 3
 4         public virtual DateTime SampleSync()
 5         {
 6             return DateTime.Now;
 7         }
 8
 9         public virtual async ValueTask SampleAsync()
10         {
11             await ValueTask.CompletedTask;
12             return DateTime.Now;
13         }
14     }

3.3、定义继承类,重写相关方法

 1     public sealed class TestService_Aop : TestService
 2     {
 3         private readonly IServiceProvider _serviceProvider0;
 4         public TestService_Aop(IServiceProvider serviceProvider0)
 5         {
 6             _serviceProvider0 = serviceProvider0;
 7         }
 8
 9         public override DateTime SampleSync()
10         {
11             var aopContext = new AopContext(_serviceProvider0,
12                 new Dictionary<string, dynamic>() { },
13                 false,
14                 true,
15                 null);
16
17             var aopInterceptor0 = _serviceProvider0.GetRequiredService();
18             if (aopInterceptor0.HasBefore) aopContext = aopInterceptor0.Before(aopContext);
19             if (aopInterceptor0.HasAopNext)
20             {
21                 if (aopInterceptor0.HasActualNext)
22                 {
23                     aopContext.ActualMethod = () => base.SampleSync();
24                 }
25                 aopContext = aopInterceptor0.Next(aopContext);
26             }
27             else
28             {
29                 if (aopInterceptor0.HasActualNext)
30                 {
31                     aopContext.ReturnValue = base.SampleSync();
32                 }
33             }
34             if (aopInterceptor0.HasAfter) aopContext = aopInterceptor0.After(aopContext);
35
36             return aopContext.ReturnValue;
37         }
38
39         public override async ValueTask SampleAsync()
40         {
41             var aopContext = new AopContext(_serviceProvider0,
42                 new Dictionary<string, dynamic>() { },
43                 true,
44                 true,
45                 null);
46
47             var aopInterceptor0 = _serviceProvider0.GetRequiredService();
48             if (aopInterceptor0.HasBefore) aopContext = await aopInterceptor0.BeforeAsync(aopContext);
49             if (aopInterceptor0.HasAopNext)
50             {
51                 if (aopInterceptor0.HasActualNext)
52                 {
53                     aopContext.ActualMethod = () => base.SampleAsync();
54                 }
55                 aopContext = await aopInterceptor0.NextAsync(aopContext);
56             }
57             else
58             {
59                 if (aopInterceptor0.HasActualNext)
60                 {
61                     aopContext.ReturnValue = await base.SampleAsync();
62                 }
63             }
64             if (aopInterceptor0.HasAfter) aopContext = await aopInterceptor0.AfterAsync(aopContext);
65
66             return aopContext.ReturnValue;
67         }
68     }

4、开整

4.1、新建项目 Mic.Aop.Generator,TargetFramework 选 netstandard2.0,引入两个分析器包

<ItemGroup>
        <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.1" PrivateAssets="all" />
        <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
            <PrivateAssets>allPrivateAssets>
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitiveIncludeAssets>
        PackageReference>
    ItemGroup>

4.2、新建类 AopGenerator,继承 ISourceGenerator 接口,实现 Execute 方法,Execute 的内容是最终的成品。

 1     /// <summary>
 2     /// 代码生成器
 3     /// summary>
 4     [Generator]
 5     public class AopGenerator : ISourceGenerator
 6     {
 7         /// <summary>
 8         /// 初始化
 9         /// summary>
10         /// <param name="context">param>
11         public void Initialize(GeneratorInitializationContext context)
12         {
13             //Debugger.Launch();
14
15             context.RegisterForSyntaxNotifications(() => new AopSyntaxReceiver());
16         }
17
18         /// <summary>
19         /// 执行
20         /// summary>
21         /// <param name="context">param>
22         public void Execute(GeneratorExecutionContext context)
23         {
24             if (context.SyntaxReceiver is AopSyntaxReceiver receiver)
25             {
26                 var aopMateData = receiver
27                     .FindAopInterceptor() // 查找所有的拦截器
28                     .GetAopMetaData(context.Compilation); //根据拦截器找到所有的类或方法,获取元数据,包含所有接口、实现类、所有属性、所有方法
29
30                 var builders = aopMateData
31                     .GetAopCodeBuilderMetaData()  //获取用于构建代码的元数据,过滤出需要的数据
32                     .Select(i => new AopCodeBuilder(i))
33                     .Distinct()
34                     .ToList();
35                 //开始生成代码
36                 foreach (var builder in builders)
37                 {
38                     context.AddSource(builder.SourceCodeName, builder.ToSourceText());
39                 }
40             }
41         }
42     }

4.3、AopSyntaxReceiver 语法树处理类,这一步获取到所有的数据:接口、类、属性、方法、参数等等等

    /// <summary>
    /// 语法接收器
    /// summary>
    sealed class AopSyntaxReceiver : ISyntaxReceiver
    {
        private const string GeneratorTagName = "AopInterceptor"; //所有拦截器需要继承的基类
        private const string IgnoreAttribute = "IgnoreAopAttribute"; //忽略aop
        /// <summary>
        /// 类列表
        /// summary>
        private readonly List<ClassDeclarationSyntax> _classSyntaxList = new List<ClassDeclarationSyntax>();
        /// <summary>
        /// 接口列表
        /// summary>
        private readonly List<InterfaceDeclarationSyntax> _interfaceSyntaxList = new List<InterfaceDeclarationSyntax>();
        /// <summary>
        /// 所有的AopInterceptor
        /// summary>
        public List<string> AopAttributeList = new List<string>();
        /// <summary>
        /// 所有的AopInterceptor
        /// summary>
        public List<ClassMetaData> AopAttributeClassMetaDataList = new List<ClassMetaData>();

        /// <summary>
        /// 访问语法树
        /// summary>
        /// <param name="syntaxNode">param>
        void ISyntaxReceiver.OnVisitSyntaxNode(SyntaxNode syntaxNode)
        {
            if (syntaxNode is InterfaceDeclarationSyntax interfaceSyntax)
            {
                this._interfaceSyntaxList.Add(interfaceSyntax);
            }

            if (syntaxNode is ClassDeclarationSyntax classSyntax)
            {
                this._classSyntaxList.Add(classSyntax);
            }
        }

        //其他代码........

    }

4.4、找到所有的拦截器

 1         /// <summary>
 2         /// 找出所有 AopInterceptor
 3         /// summary>
 4         /// <returns>returns>
 5         public AopSyntaxReceiver FindAopInterceptor()
 6         {
 7             foreach (var classSyntax in this._classSyntaxList)
 8             {
 9                 var root = classSyntax.SyntaxTree.GetRoot();
10                 var classesWithAttribute = root
11                     .DescendantNodes()
12                     .OfType<ClassDeclarationSyntax>()
13                     .ToList();
14
15                 if (!classesWithAttribute.Any())
16                     continue;
17
18                 foreach (var classDeclarationSyntax in classesWithAttribute)
19                 {
20                     if (classDeclarationSyntax.BaseList == null)
21                         continue;
22
23                     foreach (BaseTypeSyntax baseTypeSyntax in classDeclarationSyntax.BaseList.Types)
24                     {
25                         if (baseTypeSyntax.ToString().Trim() == GeneratorTagName)
26                         {
27                             AopAttributeList.Add(classDeclarationSyntax.Identifier.Text);
28
29                             var meta = GetClassMetaData(classSyntax);
30                             if (meta != null && AopAttributeClassMetaDataList.All(d => d.Name != meta.Name))
31                                 AopAttributeClassMetaDataList.Add(meta);
32                         }
33                     }
34                 }
35             }
36
37             AopAttributeList = AopAttributeList.Distinct().ToList();
38
39             return this;
40         }

4.5、找到所有接口和打了标记的class

 1         /// <summary>
 2         /// 获取所有打了标记的接口和类
 3         /// summary>
 4         /// <param name="compilation">param>
 5         /// <returns>returns>
 6         public AopMetaData GetAopMetaData(Compilation compilation)
 7         {
 8             var result = new AopMetaData(AopAttributeList, IgnoreAttribute, new List<InterfaceMetaData>(), new List<ClassMetaData>());
 9
10             if (!AopAttributeList.Any())
11                 return result;
12
13             //处理接口
14             foreach (var classSyntax in this._interfaceSyntaxList)
15             {
16                 var root = classSyntax.SyntaxTree.GetRoot();
17                 var interfaceWithAttribute = root
18                     .DescendantNodes()
19                     .OfType<InterfaceDeclarationSyntax>()
20                     .ToList();
21
22                 if (!interfaceWithAttribute.Any())
23                     continue;
24
25                 //处理接口
26                 foreach (var interfaceDeclaration in interfaceWithAttribute)
27                 {
28                     var namespaceName = interfaceDeclaration.FindParent<NamespaceDeclarationSyntax>().Name.ToString();
29                     var className = interfaceDeclaration.Identifier.Text;
30                     var properties = interfaceDeclaration.DescendantNodes().OfType<PropertyDeclarationSyntax>().ToList();
31                     var methodSyntaxs = interfaceDeclaration.DescendantNodes().OfType<MethodDeclarationSyntax>().ToList();
32
33                     //属性集合
34                     var props = properties.Select(d => new PropertyMetaData(d.Identifier.Text, d.GetAttributeMetaData())).ToList();
35                     //方法集合
36                     var methods = methodSyntaxs.Select(GetMethodMetaData).ToList();
37
38                     var interfaceMetaData = new InterfaceMetaData(namespaceName, className, interfaceDeclaration.GetAttributeMetaData(), props, methods);
39                     if (interfaceMetaData.MethodMetaData.Any() && !result.InterfaceMetaDataList.Exists(d => d.Equals(interfaceMetaData)))
40                         result.InterfaceMetaDataList.Add(interfaceMetaData);
41                 }
42             }
43
44             //处理类
45             foreach (var classSyntax in this._classSyntaxList)
46             {
47                 var root = classSyntax.SyntaxTree.GetRoot();
48                 var classesWithAttribute = root
49                     .DescendantNodes()
50                     .OfType<ClassDeclarationSyntax>()
51                     .ToList();
52
53                 if (!classesWithAttribute.Any())
54                     continue;
55
56                 foreach (var classDeclaration in classesWithAttribute)
57                 {
58                     var classMetaData = GetClassMetaData(classDeclaration);
59                     if (classMetaData == null)
60                         continue;
61
62                     if (AopAttributeList.Contains(classMetaData.Name))
63                         continue;
64
65                     if (classMetaData.MethodMetaData.Any() && !result.ClassMetaDataList.Exists(d => d.Equals(classMetaData)))
66                         result.ClassMetaDataList.Add(classMetaData);
67                 }
68             }
69
70             result.AopAttributeClassMetaDataList = AopAttributeClassMetaDataList;
71
72             return result;
73         }

4.6、获取 class 的信息:属性、方法集合、继承的接口、using引用、构造函数

 1         private ClassMetaData? GetClassMetaData(ClassDeclarationSyntax classDeclaration)
 2         {
 3             var namespaceName = classDeclaration.FindParent<NamespaceDeclarationSyntax>().Name.ToString();
 4             var className = classDeclaration.Identifier.Text;
 5             var properties = classDeclaration.DescendantNodes().OfType<PropertyDeclarationSyntax>().ToList();
 6             var methodSyntaxs = classDeclaration.DescendantNodes().OfType<MethodDeclarationSyntax>().ToList();
 7
 8             //属性集合
 9             var props = properties.Select(d => new PropertyMetaData(d.Identifier.Text, d.GetAttributeMetaData())).ToList();
10             //方法集合
11             var methods = methodSyntaxs.Select(GetMethodMetaData).ToList();
12             //实现的接口集合
13             var interfaces = classDeclaration.BaseList?.ToString().Split(':').Last().Trim().Split(',').Where(d => d.Split('.').Last().StartsWith("I")).ToList() ?? new List<string>();
14             //using 引用
15             var usingDirectiveSyntax = classDeclaration.Parent?.Parent == null ? new SyntaxList<UsingDirectiveSyntax>() : ((CompilationUnitSyntax)classDeclaration.Parent.Parent).Usings;
16             var usings = usingDirectiveSyntax.Select(d => d.ToString()).ToList();
17
18             //构造函数
19             var constructorDictionary = new List<KeyValueModel>();
20             foreach (var memberDeclarationSyntax in classDeclaration.Members)
21             {
22                 if (memberDeclarationSyntax.Kind().ToString() == "ConstructorDeclaration")
23                 {
24                     //constructorDictionary = memberDeclarationSyntax.DescendantNodes().OfType<ParameterSyntax>().ToDictionary(d => d.GetFirstToken().Text, d => d.GetLastToken().Text);
25                     constructorDictionary = memberDeclarationSyntax.DescendantNodes().OfType<ParameterSyntax>().Select(d => new KeyValueModel(d.Type?.ToString(), d.Identifier.Text)).ToList();
26                     break;
27                 }
28             }
29
30             return new ClassMetaData(namespaceName, className, classDeclaration.GetAttributeMetaData(), props, methods, interfaces, constructorDictionary, usings);
31         }

4.7、获取 method 的信息:方法名称、是否异步、是否有返回值、是否可重写、参数信息、Aop 标记集合(可能有多个)

 1         private MethodMetaData GetMethodMetaData(MethodDeclarationSyntax methodDeclarationSyntax)
 2         {
 3             var param = new List<KeyValueModel>();
 4             var properties = methodDeclarationSyntax.DescendantNodes().OfType<ParameterListSyntax>().FirstOrDefault()?.DescendantNodes().OfType<ParameterSyntax>().ToList() ?? new List<ParameterSyntax>();
 5             foreach (var parameterSyntax in properties)
 6             {
 7                 var type = parameterSyntax?.Type?.ToString();
 8                 var name = parameterSyntax?.Identifier.Text;
 9                 if (type != null && name != null)
10                     param.Add(new KeyValueModel(type, name));
11             }
12
13             var returnValue = methodDeclarationSyntax.ReturnType.ToString();
14
15             return new MethodMetaData(methodDeclarationSyntax.Identifier.Text,
16                 methodDeclarationSyntax.GetAttributeMetaData(), returnValue, param, methodDeclarationSyntax.Modifiers.ToString());
17         }

4.8、一顿操作猛如虎,现在我们获取到了所有的信息,可以开干了。这一步处理元数据,过滤出需要生成代理类的信息。

约定一些规则:

就近原则类方法上的标签 > 类上的标签 > 接口方法上的标签 > 接口上的标签,即离实际的方法越近,优先级越高。

忽略Aop:打上 [IgnoreAop] 标签

管道模式:如果一个方法打上多个Attribute,则按照管道的原则,先进后出,注意,只有最接近方法的 Attribute 才能调用 Next 方法。如果有 三个 Attribute,分别是 attribute1、attribute2、attribute3,则执行顺序是 attribute1.Before => attribute2.Before => attribute3.Before => attribute3.Next => attribute3.After => attribute2.After => attribute1.After

按照这个约定,过滤得到需要的数据

        public List<AopCodeBuilderMetaData> GetAopCodeBuilderMetaData()
        {
            //就近原则,方法 > 类 > 接口方法 > 接口

            var list = new List<AopCodeBuilderMetaData>();
            foreach (var classMetaData in ClassMetaDataList.Where(d => !AopAttributeList.Contains(d.Name)))
            {
                ////必须要可重写方法 放出错误
                //if (classMetaData.MethodMetaData.All(d => !d.CanOverride))
                //    continue;

                var methods = new List<MethodMetaData>();
                var classHasIgnore = classMetaData.HasIgnore(IgnoreAttribute);

                //实现的接口
                classMetaData.Usings.Add(classMetaData.NameSpace);
                classMetaData.InterfaceMetaData = InterfaceMetaDataList.Where(d => classMetaData.Interfaces.Contains(d.Key)
                    || classMetaData.Interfaces.SelectMany(t => classMetaData.Usings.Select(u => $"{u.Replace("using ", "").Replace(";", "")}.{t.Split('.').Last()}")).Contains(d.Key)).ToList();
                classMetaData.Usings.Remove(classMetaData.NameSpace);

                //按照就近原则过滤
                //foreach (var methodMetaData in classMetaData.MethodMetaData.Where(d => d.CanOverride))
                foreach (var methodMetaData in classMetaData.MethodMetaData)
                {
                    //忽略
                    if (methodMetaData.AttributeMetaData.HasIgnore(IgnoreAttribute))
                        continue;

                    //类方法标记
                    var methodAttrs = methodMetaData.AttributeMetaData.GetAopAttributes(AopAttributeList);
                    if (methodAttrs.Any())
                    {
                        methodMetaData.AttributeMetaData.Clear();
                        methodMetaData.AttributeMetaData.AddRange(methodAttrs);
                        methods.Add(methodMetaData);
                        continue;
                    }

                    //类标记
                    if (classHasIgnore)
                        continue;

                    var classAttr = classMetaData.AttributeMetaData.GetAopAttribute(AopAttributeList);
                    if (classAttr != null)
                    {
                        methodMetaData.AttributeMetaData.Clear();
                        methodMetaData.AttributeMetaData.Add(classAttr);
                        methods.Add(methodMetaData);
                        continue;
                    }

                    //接口标记
                    if (!classMetaData.Interfaces.Any())
                        continue;

                    //接口方法忽略
                    if (classMetaData.InterfaceMetaData.Any(d => d.MethodMetaData.FirstOrDefault(m => m.Key == methodMetaData.Key)?.AttributeMetaData.HasIgnore(IgnoreAttribute) == true))
                        continue;

                    //接口方法标记
                    var interfaceMethodAttr = classMetaData.InterfaceMetaData.Select(d => d.MethodMetaData.FirstOrDefault(m => m.Key == methodMetaData.Key)?.AttributeMetaData.GetAopAttribute(AopAttributeList))
                        .FirstOrDefault(d => d != null);

                    if (interfaceMethodAttr != null)
                    {
                        methodMetaData.AttributeMetaData.Clear();
                        methodMetaData.AttributeMetaData.Add(interfaceMethodAttr);
                        methods.Add(methodMetaData);
                        continue;
                    }

                    //接口标记
                    var interfaceAttr = classMetaData.InterfaceMetaData.Where(d => d.MethodMetaData.Any(d => d.Key == methodMetaData.Key)).Select(d => d.AttributeMetaData.GetAopAttribute(AopAttributeList))
                        .FirstOrDefault(d => d != null);
                    if (interfaceAttr != null)
                    {
                        methodMetaData.AttributeMetaData.Clear();
                        methodMetaData.AttributeMetaData.Add(interfaceAttr);
                        methods.Add(methodMetaData);
                        continue;
                    }
                }

                if (methods.Any())
                    list.Add(new AopCodeBuilderMetaData(classMetaData.NameSpace, classMetaData.Name, methods, classMetaData.Constructor, classMetaData.Usings, classMetaData.InterfaceMetaData));
            }

            return list;
        }

4.9、生成代码,生成 3.3 这样的代码。这一步就是代码拼接,StringBuilder 一把梭,需要注意的是处理不同的情况如 同步异步、有无返回值、方法的重载、拦截器的传值等。代码太原始不宜展示,感兴趣的可以去看源码。整个过程到此结束。

5、不服跑个分

加上aop标签之后,整个方法调用链是 aopbefore => aopnext => 执行实际的方法 => aopafter,一共4层,每多一层,耗时就增加,在我的电脑上跑了一下, 每增加一层调用,大概增加 20~30ns 的耗时。因此根据实际使用场景,增加了 HasBefore、HasAfter、HasAopNext、HasActualNext 这4个判断去自定义需要执行的方法。详情见1。

缓存场景:有缓存,直接 before 里获取缓存,直接返回,不需要后续的执行,此时只有before;无缓存:可以在 AopNext 中执行 ActualNext,更新缓存然后返回,或者 执行 ActualNext ,最后在 After 中更新缓存,这里可以省略一个方法调用;

业务日志:只需要执行 ActualNext,然后在 After 中写日志,这场景只有2个方法,节省2个方法,美滋滋。

SourceGenerator 使用姿势(1):生成代理类,实现简单的AOP

以直接调用同步方法为基准,36ns

直接调用同步方法:1

直接调用异步方法:2.08

缓存场景同步调用:5.47

缓存场景异步调用:7.45

4个方法火力全开:同步:3.8

4个方法火力全开:异步:13.5

代码中使用了.net core 自带的DI 获取对象,有 几十ns 的开销。

6、结尾

SourceGenerator是个好东西,我司在用的场景还有生成一些额外属性,比如 给Dto中的 枚举、字典、行政区划等自动添加 Name 属性,不用手动一个个去处理,延长键盘使用寿命。

在这里提供了一些思路,你们用来做什么呢?

本文代码传送门:https://github.com/ad313/mic

另外分享一些SourceGenerator的项目:

https://github.com/amis92/csharp-source-generators

https://github.com/Cysharp/MemoryPack

Original: https://www.cnblogs.com/ad313/p/16965418.html
Author: ad313
Title: SourceGenerator 使用姿势(1):生成代理类,实现简单的AOP

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/796984/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球