SourceGenerator 已经出来很久了,也一直在关注。之前观摩大佬 xljiulang 的 WebApiClient 使用 SourceGenerator 生成接口代理类,深受启发,准备拿过来用看看(发出白嫖的声音),写个编译期静态代理AOP。本篇重点是怎么获取元数据,得到想要的数据,生成想要的代码(往下拖到第 4 点)。
几个月前写了个demo,现在趁着有空重新整理完善了下。.net 6 新增了个 IIncrementalGenerator 进行增量编译,这个还没研究,后面再说。
我的思路是继承,生成一个类去继承需要拦截的实际类,然后重写相关的方法,此时插入额外的方法,比如 Before,After 等。这就要求相关方法必须是 可重写 的, virtual 或 override。好了,开干。
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
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |