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 条评论
登录 后参与评论

相关文章

来自专栏GreenLeaves

反射基础入门篇

1、简介 Reflection,中文翻译为反射。.Net的应用程序由以下几个部分组成: a、程序集(assembly) b、模块(moudle) c、类型(cl...

1906
来自专栏每日一篇技术文章

Swift3.0-可选值

1002
来自专栏大内老A

通过实例模拟ASP.NET MVC的Model绑定的机制:集合+字典

在本系列的前面两篇文章(《简单类型+复杂类型》、《数组》)我们通过创建的实例程序模拟了ASP.NET MVC默认使用的DefaultModelBinder对简单...

2957
来自专栏码农分享

原型模式(Prototype)

原型模式的结构 原型模式包含以下3个角色: •Prototype(抽象原型类) •ConcretePrototype(具体原型类) •Client(客户...

1123
来自专栏犀利豆的技术空间

Redis 的基础数据结构(三)对象

前两篇文章介绍了 Redis 的基本数据结构动态字符串,链表,字典,跳跃表,压缩链表,整数集合,但是使用过 Redis 的同学会发现,平时根本没有使用过这些数...

1102
来自专栏个人随笔

C# 序列化与反序列化

对象持久化到文本文件,策略是:将对象的属性值打散,拆解,分别存储。 序列化:  保存对象的"全景图"  序列化是将对象转换为可保存或可传输的格式的过程  三种:...

3909
来自专栏前端侠2.0

学习表达式树笔记 原

文章地址:  http://www.cnblogs.com/Ninputer/archive/2009/08/28/expression_tree1.html

1012
来自专栏大内老A

由for V.S. for each想到的

一直想写一系列如何提高Performance和Scalability的文章,把我的相关经验和所知道的相关的技巧同大家分享。前一阵在园子里有一篇讨论for eac...

1888
来自专栏用户3030674的专栏

Java中Json解析

首先准备一个JSON格式的字符串 * String JsonStr = "{object:{persons:" + "[{name:'呵呵',im...

2252
来自专栏程序你好

理解C#语言中相等Equality 和唯一 Identity

1022

扫码关注云+社区

领取腾讯云代金券