专栏首页林德熙的博客Roslyn 节点的 Span 和 FullSpan 有什么区别 准备创建语法树访问语法树访问方法访问表达式不同

Roslyn 节点的 Span 和 FullSpan 有什么区别 准备创建语法树访问语法树访问方法访问表达式不同

本文告诉大家在使用 Roslyn 分析代码时,使用的 Span 和 FullSpan 有什么区别

在开始读本文之前,希望大家已经了解部分关于 Roslyn 的知识,如果是通过搜索进来的,大概就是已经知道基础的写法了。如果是通过本渣的推荐看到本文,本渣会详细告诉大家如何做。

准备

先写出一个简单的类用来分析

using System;

namespace BebehersoSerdar
{
    class Foo
    {
        /// <summary>
        /// 设置或获取NawraSaw
        /// </summary>
        public string NawraSaw { get; set; }

        public void RorgiWhiseaSawrear()
        {
            Console.WriteLine(NawraSaw);
        }

        public void TurlouDismemteeka()
        {
            // 输出一个值
            Console.WriteLine(NawraSaw);// 代码需要多写没有用的注释

            // 下一句代码
        }
    }
}

创建语法树

把前面这个文件拿出来,用这个文件来创建语法树

            var file = new FileInfo(@"D:\lindexi\roslyn\BebehersoSerdar\BebehersoSerdar\Foo.cs");

            string content;

            using (var stream = new StreamReader(file.OpenRead()))
            {
                content = stream.ReadToEnd();
            }

            var tree = CSharpSyntaxTree.ParseText(content);

文件的路径就是刚才写的代码文件

通过 CSharpSyntaxTree.ParseText 就可以拿到语法树

访问语法树

为了访问语法树,需要创建一个类继承 CSharpSyntaxWalker 这里创建的类是 DowkurTicesoo 请看代码

    public class DowkurTicesoo : CSharpSyntaxWalker
    {

    }

本文说道了这里还没有告诉大家 Span 是什么,这个属性就是对应文本的第多少个字符开始和字符的长度。通过 Span 可以找到代码对应的文本。

所以在这里需要多创建一个方法,用来把 Span 转换为字符串

        public DowkurTicesoo(string content, SyntaxWalkerDepth depth = SyntaxWalkerDepth.Node) : base(depth)
        {
            Content = content;
        }

        private string Content { get; }

        public string GetText(TextSpan span)
        {
            return Content.Substring(span.Start, span.Length);
        }

访问方法

这里直接就告诉大家如何访问方法,因为只有在方法里面才可以比较直观看到 Span 和 FullSpan 的不同

通过重写方法就可以拿到一个类的所有方法,请看代码

        public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
        {
            base.VisitMethodDeclaration(node);
        }

在方法这里打断点可以看到进来两次,因为存在两个方法 RorgiWhiseaSawrear 和 TurlouDismemteeka 会进来两遍

先直接把方法的 Span 和 FullSpan 输出出来,请看代码

        public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
        {
            Console.WriteLine(GetText(node.Span));
            Console.WriteLine(GetText(node.FullSpan));
            base.VisitMethodDeclaration(node);
        }

这时运行可以看到这个输出

可以看到 Span 和 FullSpan 的一个不同是 Span 是从方法的第一个代码字符开始,和 Span 不同的是 FullSpan 是从方法的距离上一个代码结束开始的字符到方法结束的最后的字符

访问表达式

在另一个方法 TurlouDismemteeka 可以看到两个属性拿到的值的不同,因为这个方法里调用表达式,所以需要使用下面的方法拿到值

        public override void VisitExpressionStatement(ExpressionStatementSyntax node)
        {
            Console.WriteLine(GetText(node.Span));
            Console.WriteLine(GetText(node.FullSpan));
            base.VisitExpressionStatement(node);
        }

对于 RorgiWhiseaSawrear 方法,两个属性的输出只有很少的不同

Console.WriteLine(NawraSaw);
            Console.WriteLine(NawraSaw);
\r\n

也就是 Span 就是去掉了 RorgiWhiseaSawrear 的前后空白,上面的 \r\n 是告诉大家这里还有一个换行符

但是对于 TurlouDismemteeka 就可以看到明显的不相同,第二个属性可以拿到注释

Console.WriteLine(NawraSaw);
            // 输出一个值
            Console.WriteLine(NawraSaw);// 代码需要多写没有用的注释
\r\n

在 VisualStudio 可以看到的转换 FullSpan 的值是 " // 输出一个值\r\n Console.WriteLine(NawraSaw);// 代码需要多写没有用的注释\r\n"

可以看到注释下一句代码没有被引用,但是如果在 TurlouDismemteeka 的第一句代码多加一些换行,在 FullSpan 是可以转换

        public void TurlouDismemteeka()
        {
            
            // 输出一个值
            Console.WriteLine(NawraSaw);// 代码需要多写没有用的注释

            // 下一句代码
        }

这时从 VisualStudio 转换是多了换行"\r\n // 输出一个值\r\n Console.WriteLine(NawraSaw);// 代码需要多写没有用的注释\r\n",也就是引号后面多了\r\n的换行

不同

实际上在很多的方法里,使用 Span 和 FullSpan 都是没有什么区别。

用一句话来说明就是 Span 就只包括代码,而 FullSpan 包括了代码和代码附近的注释。

对于不同的结点的 Span 是不会存在值的冲突,但是对于 FullSpan 是存在多个节点的覆盖。

实际上使用 Span 转换字符串和使用 FullSpan 转换字符串的方法就和使用 ToString 差不多,请看 Roslyn NameSyntax 的 ToString 和 ToFullString 的区别

参见:Use the .NET Compiler Platform SDK syntax model

Roslyn


本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C# dontet Office Open XML Unit Converter

    Here is my code to conver between OpenXML units.

    林德熙
  • 通过公开的自动构建发布开源项目的库的安全意义

    这是比较有争议的内容,为什么我推荐开源项目的库应该采用开源的 CI 公开进行发布。本文主要来聊安全的问题,本文的观点没法完全让小伙伴信服,只能说是我自己的看法

    林德熙
  • dotnet 双缓存数据结构设计 下载库的文件写入缓存框架

    我在写一个文件下载库,这个下载库利用断点续传机制,支持多线程下载一个文件。但是文件写入只能支持单线程,我不想让网络下载需要等待磁盘写入,因此我需要先在内存做缓存...

    林德熙
  • java概念1

    public static void main(String[] args) {//其中[]也可以写在args后面,args也可以随便写成其他字母,例如asd...

    闵开慧
  • 教妹学Spring:Aware、异步编程、计划任务

    你好呀,我是沉默王二,一个和黄家驹一样身高,刘德华一样颜值的程序员(不信围观朋友圈呗)。从 2 位偶像的年纪上,你就可以断定我的码龄至少在 10 年以上,但实话...

    沉默王二
  • Art of Android Development Reading Notes 1

    《Android开发艺术探索》读书笔记 (1) 第1章 Activity的生命周期和启动模式

    宅男潇涧
  • 栈的基本实现

     此节我们在我们之前封装的动态数组的基础上(引用封装好的动态数组),实现基本的栈操作。

    wfaceboss
  • 深度学习为何起作用——关键解析和鞍点

    用户1737318
  • 深度学习为何起作用——关键解析和鞍点

    对深度学习,包括分布式表示,深度架构和易避免鞍点的理论驱动力的讨论。 这篇文章总结了Rinu Boney最近一篇博客的关键点,基于今年蒙特利尔深度学习暑期学校上...

    CSDN技术头条
  • Coder,我怀疑你并不会枚举

    使用命令javac ColorEnum.java进行编译生成class文件,然后再用命令javap -p ColorEnum.class进行反编译。

    Java旅途

扫码关注云+社区

领取腾讯云代金券