Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
vermeir_nico_introducing_net_6_getting_started_with_blazor_m.pdf
Скачиваний:
19
Добавлен:
26.06.2023
Размер:
11.64 Mб
Скачать

Chapter 10 .NET Compiler Platform

•\ Syntax trees are thread-safe and immutable. A syntax tree is a state snapshot of the code. In-framework factory methods make sure that requested changes are pushed back to the code and a new syntax tree is generated based on the latest state of the source code. Syntax trees have a lot of optimalizations in place so that new instances of a tree can be generated very fast with little memory use.

Roslyn SDK

As mentioned before, Roslyn is extendable. To be able to develop your own Roslyn analyzers, you need to install the Roslyn SDK. The SDK is part of the Visual Studio installer; it’s available as an optional item as seen in Figure 10-4.

Figure 10-4.  Installing the .NET Compiler Platform SDK

With the SDK comes the Syntax Visualizer. The Syntax Visualizer is an extra window in Visual Studio, under View Other Windows Syntax Visualizer, that lays out the syntax tree of the current open code file in Visual Studio. Its position synchronizes with your cursor in the source file. Figure 10-5 shows the visualizer docked to the side in Visual Studio 2022.

279

Chapter 10 .NET Compiler Platform

Figure 10-5.  Syntax Visualizer

280

Chapter 10 .NET Compiler Platform

Figure 10-6.  Roslyn project templates

The Syntax Visualizer is a great visual aid when working with the syntax tree. After installing the .NET Compiler Platform SDK, you will have access to new project templates in Visual Studio.

With these templates, you can build your own analyzers, code fixes, or code refactorings, both as a stand-alone console application and as a Visual Studio extension in the VSIX format. These templates are available for both C# and Visual Basic.

281

Chapter 10 .NET Compiler Platform

Creating anAnalyzer

Let’s create a stand-alone code analysis. Notice that the code analysis tools need to be written in .NET Framework; don’t worry about that; they do support analyzing .NET 6 code. The default template queries the available version of MSBuild on your system and lists them to select which version you want to analyze code against. Figure 10-7 shows the default output when we run the unchanged template; this list might be different for you depending on what is installed on your system.

Figure 10-7.  Listing the available MSBuild instances

The logic of detecting MSBuild instances is abstracted away by the Roslyn SDK; all we need to do is call MSBuildLocator.QueryVisualStudioInstances().ToArray() to get a list of versions installed. Let’s empty the Main method and start implementing a code analyzer ourselves.

When analyzing code, we will need a SyntaxTree object. A SyntaxTree holds a parsed representation of a code document. In our example, we will inspect a piece of code and print the using statements in the console. Once we have our syntax tree

parsed, we can extract a CompilationUnitSyntax object. This object represents our code document, divided into members, using directives and attributes.

Listing 10-1 shows how to get the syntax tree and compilation unit from a piece of code.

282

Chapter 10 .NET Compiler Platform

Listing 10-1.  Generating the syntax tree and compilation unit

static Task Main(string[] args)

{

const string code = @"using System; using System.Linq; Console. WriteLine(""Hello World"");";

SyntaxTree tree = CSharpSyntaxTree.ParseText(code); CompilationUnitSyntax root = tree.GetCompilationUnitRoot();

We are using a very simple code example to get the point across. We parse the code into a SyntaTree and extract the CompilationUnitRoot from there.

Next we will need a CSharpSyntaxWalker object. A syntax walker is an implementation of the Visitor design pattern. The Visitor pattern describes a way to decouple an object structure from an algorithm; more information on the pattern is found at https://en.wikipedia.org/wiki/Visitor_pattern.

The CSharpSyntaxWalker class is an abstract class so we will need to create our own class that inherits from CSharpSyntaxWalker. For this example, we add a class called UsingDirectivesWalker. Listing 10-2 shows the code for this class.

Listing 10-2.  Custom using directive syntax walker

class UsingDirectivesWalker : CSharpSyntaxWalker

{

public override void VisitUsingDirective(UsingDirectiveSyntax node)

{

Console.WriteLine($"Found using {node.Name}.");

}

}

In this example, we are overriding the VisitUsingDirective method from the CSharpSyntaxWalker base class. The base class comes with many override methods that each visits a specific type of syntax nodes. The VisitUsingDirective method visits all using directives in our syntax tree. The complete list of methods that can be overwritten is found at https://docs.microsoft.com/en-us/dotnet/api/microsoft. codeanalysis.csharp.csharpsyntaxwalker.

For each using node we visit, we print its name. All there is left now is to use this custom syntax walker. Listing 10-3 shows the complete Main method.

283

Chapter 10 .NET Compiler Platform

Listing 10-3.  Using the UsingDirectivesWalker

static Task Main(string[] args)

{

const string code = @"using System; using System.Linq; Console. WriteLine(""Hello World"");";

SyntaxTree tree = CSharpSyntaxTree.ParseText(code); CompilationUnitSyntax root = tree.GetCompilationUnitRoot();

var collector = new UsingDirectivesWalker(); collector.Visit(root);

Console.Read();

return Task.CompletedTask;

}

We instantiate our new syntax walker class and call its Visit method, passing in the

CompilationUnitSyntax. This triggers the methods in the CSharpSyntaxWalker base class, from which one is overwritten in our own syntax walker class. This results in the output visible in Figure 10-8.

Figure 10-8.  Analyzer output

This has been a very simple example of how to extract a specific piece of code from a code snippet. This should help you get started with Roslyn. If you want to read more and dive deeper into Roslyn, the complete Roslyn documentation is a great resource: https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/.

284