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 ...
随机推荐
- 10.Java异常问题
目录介绍 10.0.0.1 见过哪些运行时异常?异常处理机制知道哪些?从异常是否必须需要被处理的角度来看怎么分类? 10.0.0.2 运用Java异常处理机制?异常处理的原理?Java中检查异常和非检 ...
- [MySQL]流程控制语句
[版权声明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://www.cnblogs.com/cnb-yuchen/p/17991087 出自[进步*于辰的博客] 参考笔记三,P ...
- KingbaseES V8R6 几种不同的表复制方式
前言 当数据库遇到未知问题,有时候无法入手分析,在非生产数据库或者征得客户同意获得特殊时间,需要重建表解决,下面提供了多种不同的复制表的方法,我们了解一下他们的差异. 测试 1.CREATE TABL ...
- 7 HTML锚点应用
7 锚点应用 锚点( anchor )是超链接的一种应用,也叫命名锚记,锚点可以像一个定位器一样,可以实现页面内的链接跳转,运用相当普遍.例如,我们有一个网页,由于内容太多,导致页面很长,而且里面的内 ...
- Manacher小记
目录 前言 洛谷 3805[模板]manacher算法 题目 分析 代码 洛谷 4555 最长双回文串 题目 分析 代码 洛谷 1659 拉拉队排练 题目 分析 代码 前言 皆移植于原csdn博客,略 ...
- vue3中的样式为什么加上scoped不生效
<style>标签添加scoped属性时,Vue会自动为该组件内的所有元素添加一个独特的数据属性,例如data-v-f3f3eg9.同时,它也会修改你的CSS选择器,使得它们只匹配带有这个 ...
- 使用OHOS SDK构建opus
参照OHOS IDE和SDK的安装方法配置好开发环境. 从github下载源码. 执行如下命令: git clone --depth=1 https://github.com/xiph/opus 进入 ...
- Python 简介和用途
什么是Python? Python是一种流行的编程语言,由Guido van Rossum创建,并于1991年发布. 它用于以下领域: 网页开发(服务器端) 软件开发 数学 系统脚本编写 Python ...
- C#-GroupBox包含控件,如何获取这些控件的名称
您可以使用 Enumerable.OfType在GroupBox中查找和投射您的RadioButtons: var radioButtons = groupBox1.Controls.OfType&l ...
- OS常用功能--持续更新
import os # 拼接路径 print(os.path.join('a', 'b', 'c')) # 获取当前路径 print(os.getcwd()) # 在当前文件夹创建文件夹a # os. ...