
- •Table of Contents
- •About the Author
- •Acknowledgments
- •Introduction
- •Version Support
- •Supported Versions
- •A Unified Platform
- •Roadmap
- •Supported Operating Systems
- •Command Line Interface
- •Desktop Development
- •Blazor
- •MAUI
- •Wrapping Up
- •.NET 6 Architecture
- •Runtimes
- •CoreCLR
- •Mono
- •WinRT
- •Managed Execution Process
- •Desktop Packs
- •Wrapping Up
- •Dotnet New
- •Dotnet Restore
- •NuGet.config
- •Dotnet Build
- •Dotnet Publish
- •Dotnet Run
- •Dotnet Test
- •Using the CLI in GitHub Actions
- •Other Commands
- •Wrapping Up
- •WinAPI
- •WinForms
- •STAThread
- •WinForms Startup
- •DPI Mode
- •Responding to Scale Events
- •Visual Styles
- •Text Rendering
- •The Message Loop
- •The Form Designer
- •WPF Startup
- •XAML Layout
- •Visual Tree
- •Data Binding
- •Windows App SDK
- •Building a Windows App SDK application
- •Using Windows APIs with Windows App SDK
- •Packaging
- •Migrating to .NET 6
- •Upgrade Assistant
- •Wrapping Up
- •Blazor WebAssembly
- •Creating a Blazor Wasm Project
- •Blazor Progressive Web Apps
- •Exploring the Blazor Client Project
- •Blazor in .NET 6
- •Blazor Component System
- •Creating Blazor Pages
- •Running a Blazor App
- •Blazor Server
- •SignalR
- •Blazor Desktop
- •Wrapping Up
- •Project Structure
- •Exploring MAUI
- •The Cross-Platform World
- •Application Lifecycle
- •MVVM
- •MVVM Toolkit
- •Wrapping Up
- •Model-View-Controller
- •Routing
- •Views
- •Controllers
- •Controller-Based APIs
- •Minimal APIs
- •Wrapping Up
- •Web Apps
- •Creating an App Service
- •Static Web Apps
- •Web App for Containers
- •Docker
- •Azure Functions
- •Deploying Azure Functions
- •Wrapping Up
- •Record Types
- •Monolith Architecture
- •Microservices
- •Container Orchestration
- •Kubernetes
- •Docker Compose
- •Dapr
- •Installing Dapr
- •Dapr State Management
- •Wrapping Up
- •Roslyn
- •Compiler API
- •Diagnostic API
- •Scripting API
- •Workspace API
- •Syntax Tree
- •Roslyn SDK
- •Source Generators
- •Writing a Source Generator
- •Debugging Source Generators
- •Wrapping Up
- •Garbage Collector
- •The Heap
- •The Stack
- •Garbage Collection
- •A Look at the Threadpool
- •Async in .NET 6
- •Await/Async
- •Cancellations
- •WaitAsync
- •Conclusion
- •Index
CHAPTER 10
.NET Compiler Platform
A part of the strength and flexibility of .NET comes from its compiler platform. Most people have known it under its project name Roslyn. With the compiler platform, developers can analyze their code, enforce coding guidelines, and more. Besides Roslyn, Microsoft has also introduced source generators. Source generators leverage Roslyn to generate code at compile time and include that generated code into the compilation.
Roslyn
Developers rely heavily on their tools to help their development. Just look at what Visual Studio does to help you write better code, or look at the rich ecosystem of Visual Studio extensions. IDE features like IntelliSense and Find All References need an understanding of the current code base; this is typically information that a compiler can provide. Compilers used to be black boxes that took your source code and transformed it into, in our case, intermediate language. With Roslyn, Microsoft aimed to open up the compiler platform and provide it with an API set for everyone to use to write code enhancing tools.
With Roslyn, we can write analyzers and code fixes. Analyzers look at your code and notify you when you write a piece of code that is not according to what the analyzer knows. .NET even ships with a default set of Analyzers; just open a new .NET 6 project and use solution explorer to have a look at Dependencies Analyzers, as shown in Figure 10-1.
275
© Nico Vermeir 2022
N. Vermeir, Introducing .NET 6, https://doi.org/10.1007/978-1-4842-7319-7_10

Chapter 10 .NET Compiler Platform
Figure 10-1. Built-in analyzers
As you can see, Roslyn can provide numerous checks for best practices. The different icons point to the different severity levels of the checks. Some are warnings; others are errors and will cause builds to fail. Code fixes on the other hand provide proposals to the developer on how to refactor the code to fix an analyzer warning. A code fix can, for example, turn a For Each block into a simple LINQ statement by the push of a button. Figure 10-2 shows an example of this.
276

Chapter 10 .NET Compiler Platform
Figure 10-2. Using an analyzer to convert a For Each to LINQ
Roslyn ships with an SDK. That SDK provides us with all the tools we need to hook into the compiler pipeline. From the SDK we get compiler APIs, diagnostic APIs, scripting APIs, and workspace APIs.
Compiler API
The Compiler API contains the actual language-specific code compiler; in case of C#, this would be csc.exe. The API itself contains object models for each phase in the compiler pipeline. Figure 10-3 shows a diagram of the compiler pipeline.
Figure 10-3. Compiler pipeline (Source: Microsoft)
277
Chapter 10 .NET Compiler Platform
Diagnostic API
The diagnostic API is what gives us the “squiggly lines” in our code. It’s an API that analyzes syntax, assignments, and semantics based on Roslyn analyzers. It generates warnings or errors. This API can be used by linting tools to, for example, fail a build when certain team guidelines are not respected in a pull request.
Scripting API
This is part of the compiler layer and can be used to run code snippets as scripts. This is used by, for example, the C# Read, Evaluate, Print Loop, or REPL to run snippets of C# against a running assembly.
Workspace API
The workspace API provides the entry point for code analysis and refactorings over entire solutions. It powers IDE functions like Find All References and Formatting.
Syntax Tree
The syntax tree is a data structure exposed by the compiler API. It’s a representation of the syntax structure of your code. The syntax tree enables tools to process and analyze the structure of your code. Using the syntax tree add-ins and IDE software can detect patterns in your code and change it when deemed necessary. A syntax tree has three characteristics:
•\ |
It contains the full information of the code that was typed by the |
|
developers, including comments, compiler pre-directives, and |
|
whitespaces. |
•\ |
The exact original code can be reconstructed from a syntax tree. |
|
A syntax tree is an immutable construct that was parsed from the |
|
original source code. In order to provide the full power of analytics |
|
and code refactoring, the syntax tree needs to be able to reproduce |
|
the exact code it was parsed from. |
278