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

  • SourceGenerator 使用姿势(1):生成代理类,实现简单的AOP已关闭评论
  • 45 次浏览
  • A+
所属分类:.NET技术
摘要

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

SourceGenerator 已经出来很久了,也一直在关注。之前观摩大佬 SourceGenerator 使用姿势(1):生成代理类,实现简单的AOPxljiulang 的 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 这个接口,这里加了只是为了约束。

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

 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、定义拦截器

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

 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个方法,美滋滋。

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