SourceGenerator 使用姿势(1):生成代理类,实现简单的AOP
阅读原文时间:2023年07月08日阅读:3

SourceGenerator 已经出来很久了,也一直在关注。之前观摩大佬 xljiulang 的 WebApiClient 使用 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 这个接口,这里加了只是为了约束。

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 }

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 MethodInputParam { get; private set; }
18
19 /// 20 /// 实际方法执行结果,可能是 Task 21 ///
22 public Func 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 methodInputParam, bool isTask, bool hasReturnValue, Func 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、定义拦截器

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 }

定义接口

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() { },
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() { },
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,引入两个分析器包

all runtime; build; native; contentfiles; analyzers; buildtransitive

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

1 ///

2 /// 代码生成器 3 ///
4 [Generator]
5 public class AopGenerator : ISourceGenerator
6 {
7 /// 8 /// 初始化 9 ///
10 ///
11 public void Initialize(GeneratorInitializationContext context)
12 {
13 //Debugger.Launch();
14
15 context.RegisterForSyntaxNotifications(() => new AopSyntaxReceiver());
16 }
17
18 /// 19 /// 执行 20 ///
21 ///
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 ///

2 /// 找出所有 AopInterceptor 3 ///
4 ///
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()
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 ///

2 /// 获取所有打了标记的接口和类 3 ///
4 ///
5 ///
6 public AopMetaData GetAopMetaData(Compilation compilation)
7 {
8 var result = new AopMetaData(AopAttributeList, IgnoreAttribute, new List(), new List());
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()
20 .ToList();
21
22 if (!interfaceWithAttribute.Any())
23 continue;
24
25 //处理接口
26 foreach (var interfaceDeclaration in interfaceWithAttribute)
27 {
28 var namespaceName = interfaceDeclaration.FindParent().Name.ToString();
29 var className = interfaceDeclaration.Identifier.Text;
30 var properties = interfaceDeclaration.DescendantNodes().OfType().ToList();
31 var methodSyntaxs = interfaceDeclaration.DescendantNodes().OfType().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()
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().Name.ToString();
4 var className = classDeclaration.Identifier.Text;
5 var properties = classDeclaration.DescendantNodes().OfType().ToList();
6 var methodSyntaxs = classDeclaration.DescendantNodes().OfType().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();
14 //using 引用
15 var usingDirectiveSyntax = classDeclaration.Parent?.Parent == null ? new SyntaxList() : ((CompilationUnitSyntax)classDeclaration.Parent.Parent).Usings;
16 var usings = usingDirectiveSyntax.Select(d => d.ToString()).ToList();
17
18 //构造函数
19 var constructorDictionary = new List();
20 foreach (var memberDeclarationSyntax in classDeclaration.Members)
21 {
22 if (memberDeclarationSyntax.Kind().ToString() == "ConstructorDeclaration")
23 {
24 //constructorDictionary = memberDeclarationSyntax.DescendantNodes().OfType().ToDictionary(d => d.GetFirstToken().Text, d => d.GetLastToken().Text);
25 constructorDictionary = memberDeclarationSyntax.DescendantNodes().OfType().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();
4 var properties = methodDeclarationSyntax.DescendantNodes().OfType().FirstOrDefault()?.DescendantNodes().OfType().ToList() ?? new List();
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、不服跑个分(bushi)

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

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

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

以直接调用同步方法为基准,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