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

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

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

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

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

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

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

 1     public class AopInterceptor : Attribute, IAopInterceptor
 2     {
 3         /// <summary>
 4         /// 是否执行 Before
 5         /// </summary>
 6         public bool HasBefore { get; set; }
 7         /// <summary>
 8         /// 是否执行 After
 9         /// </summary>
10         public bool HasAfter { get; set; }
11         /// <summary>
12         /// 是否执行 Aop 的 Next
13         /// </summary>
14         public bool HasAopNext { get; set; }
15         /// <summary>
16         /// 是否执行实际的方法
17         /// </summary>
18         public bool HasActualNext { get; set; }
19 
20         /// <summary>
21         /// 默认执行所以方法
22         /// </summary>
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<AopContext> 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<AopContext> 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<AopContext> 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     /// <summary>
 2     /// Aop 上下文
 3     /// </summary>
 4     public struct AopContext
 5     {
 6         /// <summary>
 7         /// 是否是异步
 8         /// </summary>
 9         public bool IsTask { get; private set; }
10         /// <summary>
11         /// 是否有返回值
12         /// </summary>
13         public bool HasReturnValue { get; private set; }
14         /// <summary>
15         /// 方法输入参数
16         /// </summary>
17         public Dictionary<string, dynamic> MethodInputParam { get; private set; }
18 
19         /// <summary>
20         /// 实际方法执行结果,可能是 Task
21         /// </summary>
22         public Func<dynamic> ActualMethod { get; set; }
23         /// <summary>
24         /// 返回值,具体的值
25         /// </summary>
26         public dynamic ReturnValue { get; set; }
27         /// <summary>
28         /// 异常信息
29         /// </summary>
30         public Exception Exception { get; set; }
31         /// <summary>
32         /// IServiceProvider
33         /// </summary>
34         public IServiceProvider ServiceProvider { get; private set; }
35 
36         /// <summary>
37         /// 初始化
38         /// </summary>
39         /// <param name="serviceProvider"></param>
40         /// <param name="methodInputParam"></param>
41         /// <param name="isTask"></param>
42         /// <param name="hasReturnValue"></param>
43         /// <param name="actualMethod"></param>
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         /// <summary>
54         /// 执行实际方法 异步
55         /// </summary>
56         /// <returns></returns>
57         public async ValueTask<AopContext> 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         /// <summary>
73         /// 执行实际方法 同步
74         /// </summary>
75         /// <returns></returns>
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     /// <summary>
 2     /// 常规服务,执行所有方法
 3     /// </summary>
 4     public class SampleAttribute : AopInterceptor
 5     {
 6         /// <summary>执行前操作,同步方法调用</summary>
 7         /// <param name="context"></param>
 8         /// <returns></returns>
 9         public override AopContext Before(AopContext context)
10         {
11             Console.WriteLine("Before...");
12             return base.Before(context);
13         }
14 
15         /// <summary>执行前操作,异步方法调用</summary>
16         /// <param name="context"></param>
17         /// <returns></returns>
18         public override ValueTask<AopContext> 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         /// <summary>执行后操作,异步方法调用</summary>
31         /// <param name="context"></param>
32         /// <returns></returns>
33         public override ValueTask<AopContext> AfterAsync(AopContext context)
34         {
35             Console.WriteLine("AfterAsync...");
36             return base.AfterAsync(context);
37         }
38 
39         /// <summary>执行方法,同步方法调用</summary>
40         /// <param name="context"></param>
41         /// <returns></returns>
42         public override AopContext Next(AopContext context)
43         {
44             Console.WriteLine("Next...");
45             return base.Next(context);
46         }
47 
48         /// <summary>执行方法,异步方法调用</summary>
49         /// <param name="context"></param>
50         /// <returns></returns>
51         public override ValueTask<AopContext> 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<DateTime> 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<DateTime> 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<SampleAttribute>();
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<DateTime> 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<SampleAttribute>();
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>all</PrivateAssets>
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
        </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个方法,美滋滋。

 

 

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

 

posted @ 2022-12-08 15:02  ad313  阅读(1414)  评论(5编辑  收藏  举报