IIncrementalGenerator 解析 ValueTuple 的定义
本文将告诉大家如何在分析器里面解析代码里面对于 ValueTuple 的定义,包括如何获取 ValueTuple 里面的 Item 的类型和命名
开始之前先创建一个用来被分析的项目,在这个项目里面定义 Foo1 类型,然后再定义 F2 方法,设置 F2 方法的返回值是一个 ValueTuple 类型,如以下代码
public class Foo1
{
public (int x, int) F2()
{
return default;
}
}
本文将使用此作为例子,告诉大家如何解析 ValueTuple 的定义,也就是获取 F2 方法返回值类型的定义
先编写语法过滤,只让方法定义的语法通过,如以下代码
[Generator(LanguageNames.CSharp)]
public class CodeCollectionIncrementalGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var incrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((node, _) =>
{
// 只读取方法定义。这里例子是读取一个方法的返回值
return node.IsKind(SyntaxKind.MethodDeclaration);
}, (syntaxContext, _) =>
{
... // 忽略代码
});
... // 忽略代码
}
因为本文是使用分析 F2 方法的返回值作为例子,因此上面代码只让方法定义的语法通过
接下来获取方法的返回值,如以下代码
var incrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((node, _) =>
{
// 只读取方法定义。这里例子是读取一个方法的返回值
return node.IsKind(SyntaxKind.MethodDeclaration);
}, (syntaxContext, _) =>
{
// 转换为语义
IMethodSymbol methodSymbol =
syntaxContext.SemanticModel.GetDeclaredSymbol(syntaxContext.Node) as IMethodSymbol;
if (methodSymbol is null)
{
// 理论上不会进入这个代码,前面判断方法定义
return string.Empty;
}
// 获取方法返回类型
ITypeSymbol methodSymbolReturnType = methodSymbol.ReturnType;
if (methodSymbolReturnType is INamedTypeSymbol namedTypeSymbol)
{
}
... // 忽略代码
}).Where(t => !string.IsNullOrEmpty(t));
拿到方法返回值,可以进行判断 ValueTuple 类型,判断方法是通过先判断是否值类型,再判断 Tuple 元素的数量
// 由于 ValueTuple 是值类型,因此可以快速判断是否值类型
if (namedTypeSymbol.IsValueType && namedTypeSymbol.TupleElements.Length > 0)
{
}
获取 ValueTuple 语义上定义的各个 Item 的类型和命名可以通过遍历 TupleElements 属性
foreach (var tupleElement in namedTypeSymbol.TupleElements)
{
// 如此可以获取每一个类型
var tupleElementType = tupleElement.Type;
}
如果用户代码里面没有给 Item 命名,将会自动填充默认的 Item1 等默认命名,如果想要获取原来代码的定义,可以获取语法内容,如以下代码
var code = namedTypeSymbol.DeclaringSyntaxReferences[0].GetSyntax().ToString();
以下是 CodeCollectionIncrementalGenerator 的全部代码,可以创建出一个 Foo 类型,用来输出 Foo1 的 F2 方法的返回代码
[Generator(LanguageNames.CSharp)]
public class CodeCollectionIncrementalGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var incrementalValuesProvider = context.SyntaxProvider.CreateSyntaxProvider((node, _) =>
{
// 只读取方法定义。这里例子是读取一个方法的返回值
return node.IsKind(SyntaxKind.MethodDeclaration);
}, (syntaxContext, _) =>
{
// 转换为语义
IMethodSymbol methodSymbol =
syntaxContext.SemanticModel.GetDeclaredSymbol(syntaxContext.Node) as IMethodSymbol;
if (methodSymbol is null)
{
// 理论上不会进入这个代码,前面判断方法定义
return string.Empty;
}
// 获取方法返回类型
ITypeSymbol methodSymbolReturnType = methodSymbol.ReturnType;
if (methodSymbolReturnType is INamedTypeSymbol namedTypeSymbol)
{
// 由于 ValueTuple 是值类型,因此可以快速判断是否值类型
if (namedTypeSymbol.IsValueType && namedTypeSymbol.TupleElements.Length > 0)
{
foreach (var tupleElement in namedTypeSymbol.TupleElements)
{
// 如此可以获取每一个类型
var tupleElementType = tupleElement.Type;
}
var code = namedTypeSymbol.DeclaringSyntaxReferences[0].GetSyntax().ToString();
return code;
}
}
return "";
}).Where(t => !string.IsNullOrEmpty(t));
context.RegisterImplementationSourceOutput(incrementalValuesProvider,
(productionContext, provider) =>
{
var text = provider;
var code = @"using System;
namespace LainewihereJerejawwerye
{
public static class Foo
{
public static void F1()
{
Console.WriteLine(""Foo1.F2 方法返回值是" + text + @""");
}
}
}";
productionContext.AddSource("Demo", code);
});
}
}
}
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin ed913bc50dcdbdf67bd387cd49d0cfd2a95b4ede
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin ed913bc50dcdbdf67bd387cd49d0cfd2a95b4ede
获取代码之后,进入 LainewihereJerejawwerye 文件夹
更多源代码生成,请看官方的 Source Generators Cookbook
更多关于我博客请参阅 博客导航
IIncrementalGenerator 解析 ValueTuple 的定义的更多相关文章
- AMF解析之数据类型定义 (转)
目录(?)[-] OpenRTMFPCumulus Primer15AMF解析之数据类型定义 数据类型 undefined Type null Type false type true type in ...
- ES5:深入解析如何js定义类或对象。
1.原始方式 var oCar = new Object; oCar.color = "blue"; oCar.showColor = function(){alert(this ...
- C#匿名类型和动态解析减少定义传输类模板
C#作为强类型语言,在序列化和反序列化(json)场景中对字符串解析常常需要定义强类型模板,造成编码上的繁琐.其实可以使用匿名类型和动态解析减少json序列化时候的数据模板定义: string a = ...
- XML概念定义以及如何定义xml文件编写约束条件java解析xml DTD XML Schema JAXP java xml解析 dom4j 解析 xpath dom sax
本文主要涉及:xml概念描述,xml的约束文件,dtd,xsd文件的定义使用,如何在xml中引用xsd文件,如何使用java解析xml,解析xml方式dom sax,dom4j解析xml文件 XML来 ...
- Kafka:ZK+Kafka+Spark Streaming集群环境搭建(十四)定义一个avro schema使用comsumer发送avro字符流,producer接受avro字符流并解析
参考<在Kafka中使用Avro编码消息:Consumer篇>.<在Kafka中使用Avro编码消息:Producter篇> 在了解如何avro发送到kafka,再从kafka ...
- Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析
Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析 本文简要介绍了基于 Spring 的 web project 的启动流程,详细分析了 Spring 框架将开发人员基于 XML ...
- 使用newtonsoft完美序列化WebApi返回的ValueTuple
由于开发功能的需要,又懒得新建太多的class,所以ValueTuple是个比较好的偷懒方法,但是,由于WebApi需要返回序列化后的json,默认的序列化只能将ValueTuple定义的各个属性序列 ...
- SpringMVC视图解析器
SpringMVC视图解析器 前言 在前一篇博客中讲了SpringMVC的Controller控制器,在这篇博客中将接着介绍一下SpringMVC视 图解析器.当我们对SpringMVC控制的资源发起 ...
- 通俗易懂的 JSon解析处理
1.主要用到的类: 主要用到了JavaScriptSerializer类,该类在System.Web.Script.Serialization命名空间(在System.Web.Extensions.d ...
- PERL/LEX/YACC技术实现文本解析--XML解析
继周六的p_enum.pl后,再来一篇说说我用perl做的lex,yacc工具.之前说了,我学习lex和yacc的最初动机是为了做个C语言解释器的SHELL:但后来工作中的实际需要也是制作perl版l ...
随机推荐
- proteus之四状态锁定器
proteus之四状态锁定器 1.实验原理 利用4071(或门)的锁定功能,当输入为1时输出结果锁定为1,使结果锁定在这个地方.4028(BCD译码器)将输入转化为输出,利用输出反馈到或门用于自锁. ...
- 自定义AXI总线IP之补全寄存器的输入输出配置
自定义AXI总线IP之补全寄存器配置输入和输出 1.实验目的 在使用默认的AXI4的配置时,不会有寄存器的配置,无法配置端口的输入还是输出.根据前面的AXI总线的理解,这里通过仲裁器判断,将AXI4的 ...
- Unicode编码解码的全面介绍
1. Unicode的起源和发展 Unicode是一个国际标准,旨在统一世界上所有文字的表示方式.它最初由Unicode协会创立,解决了不同字符集之间的兼容性问题.Unicode的发展经历了多个版本, ...
- 算法学习笔记【8】| 单调队列优化DP
单调队列:就是滑动窗口,可以求出定长 RMQ,时间复杂度线性. 优化 DP 首先把dp方程写成这个样子: 或者其他运算f[i]=max(或者其他运算){f[j]+calc(i,j)}<scrip ...
- SQL Server表分区-水平分区3
目录 一.常用分区步骤 1.创建文件组 2.创建数据文件到文件组里面 3.使用图形界面向导创建分区表(不推荐) 3.使用T-SQL构建分区函数与分区方案(推荐) [3.1]建表时构造 [3.2]已有表 ...
- 关于 ThreadLocal 你需要知道的几点
一.ThreadLocal是什么? 一个类对象类型,提供属线程本地变量,也就是同一个变量对不同线程保存了不同的值,但是和线程自身定义的自属变量不同. 通常以私有静态类型定义,用以保存特定线程特定状态属 ...
- OpenHarmony标准系统开机时长优化
简介 万物互联时代,产品性能至关重要,而系统启动时间是系统性能的重要组成部分,因为用户必须等待系统启动完成后才能使用设备.对于经常需要进行冷启动的汽车等设备而言,较短的启动时间至关重要(没有人喜欢在等 ...
- 今晚19:00知识赋能第2期直播丨OpenHarmony智能家居项目之控制面板界面设计
OpenAtom OpenHarmony(以下简称"OpenHarmony")开源开发者成长计划项目自 2021 年 10 月 24 日上线以来,在开发者中引发高度关注. 成长计划 ...
- Django集成layui 的 layedit 之图片上传接口
# a.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- openGauss 2.1.0 闪回特性
openGauss 2.1.0 闪回特性 openGauss 2.1.0 于 2021 年 9 月 30 日发布,是 openGauss 的一个 Preview 版本,该版本生命周期仅为半年.该版本的 ...