A brief discussion on source code generation technology (Source Generators)

Even though .NET5 has been released for many years, many people are still not very familiar with this dazzling new technology – Source Generators. If you are interested, you can spend 5 minutes to watch my white talk. .

8ac5e755576c51b6765a9a745cf112f3.jpeg

When I first saw this technology, it even triggered an “orgasm” in my head: I no longer have to worry about the limitations of the proxy class; it is more convenient for us to write code through translation; the performance of open source libraries is further improved; annotations are weakened The impact of intrusions, and even comments are used; template customization? Call it T10086.

With the fantasy of technology pie in mind, I finally climbed up on my chair and downloaded the preview version of VS as I was in the late stage of lazy cancer. I couldn’t wait to open the demo. When I was about to try it out, suddenly VS compiled and reported an error? ? ,! ! ,? ? It collapsed. I gave up after fighting for an hour. The brainstorm faded away. When I mentioned SG again (I wrote Source Generators lazily), it was in an article by Natasha: The technology is eye-catching, but the application is not worth it.

61fba795ec47e3e686f7b36277873a64.png

I hung around for a long time, until the ninth person in the group said that SG was available, and the authors of other open source libraries brought a wave of new prospects in a few words, so I thought about it for two nights and decided to try it again. I picked an auspicious day, uninstalled the preview version, upgraded VS to the latest version, downloaded the demo, and started running it. There was no exception in VS, the console opened in seconds, and the Hello World! font was clearly visible. I guess everything is fine this time. . Through discussion and research in the group, in order not to owe technical debt, here I will introduce the SG technology as a whole:

c5ada94128c385e9e5534fd29fde9453.jpeg

Quoting an official paragraph to give a technical explanation:

Source Generator is a new type of component that C# developers can write that allows you to do two things: Retrieve a Compilation object that represents all user code being compiled. This object can be inspected, and you can write code that works with a syntactic and semantic model of the code being compiled, much like today’s analyzers. Generates C# source files that can be added to the Compilation object during compilation. In other words, you can provide other source code as input to the compilation when compiling your code. Source generators are .NET Standard 2.0 assemblies that are loaded by the compiler along with any analyzers. It can be used in an environment where .NET Standard components can be loaded and run.

Here we first exclude a range:

1. Code optimization

2. Log injection

3. IL weaving

4. Call bit rewriting

The above are functions that SG clearly does not support. At the same time, the source code generator is not an analyzer, so please don’t get confused.

The main working unit of SG is the ISourceGenerator interface. Its Execute method parameter is the context carrying the Compilation object. What is Compilation? Students who have written dynamic compilation may know that this is a collection of compilation information constructed before Emit is issued, including Compilation options, syntax tree collections, various compilation flags, etc., Compilation, as an abstract structure of compilation information for each language, is capable of supporting language platforms such as VB/F#. In addition, if the syntax tree collection of Compilation is allowed to be replaced, it can also be replaced. Doing a lot of intrusive operations, such as building an AOP, don’t get too happy too early, read on.

By default, the generator that implements ISourceGenerator cannot see the IDE’s perception. All information will be collected only when generating. The existing version of SG has limited functions. If you want to modify the code that has been written Impossible. At best, it can be combined with some categories to add functions. Currently, all operations are additions, so the AOP mentioned above still needs to be delegated.

1b5c5307aa77aedca999a940d20a29f0.jpeg

Let’s take a look at the official news. The official has discussed new requirements with a group of ruthless people (party A such as grpc / Razor / Blazor). In the new version, the initialization context GeneratorInitializationContext will be used to monitor files, and MSBuild related attributes will also be combined to improve the files. Output and other functions. There is a rather disgusting problem. How to debug breakpoints after file output and how breakpoints work still need to be solved. Let me say one more thing here, the official design of some new functions has not yet been decided.

So at present, what benefits will the official get from it:

  • ASP.NET: Reduced startup time.

  • Blazor and Razor: Greatly reduces workload

  • Serialization / GRPC / Azure / SWIG are all used

In order to quickly adapt to this technology, I set a small goal and briefly walked through the implementation of static AOP. The problems stated next may be the problems that some people are currently encountering (the following content is composed of questions and discussions from group friends, open source library authors, and personal excavations):

4aa46ebd96c97eeddbd3e5570e89eeef.jpeg

1. Just when I wrote the colon of the question above, a group friend asked a question, why can’t my project run and there is no prompt?

After looking at his screenshots, I determined that he was not very clear about this reference structure. Prepare:

Console A, class library B;

A writes test code, B writes code analysis and generation;

A references B; B references Roslyn-related libraries;

Pay attention to the attributes of the node referenced by A.

<ItemGroup>
        <ProjectReference Include="B.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

2. How to get the class I defined?

First, implement the ISourceGenerator interface

1. Read the .cs file through AdditionalFiles of SourceGeneratorContext.

2. Obtain the syntax tree collection through the Compilation of SourceGeneratorContext.

3. The official recommendation is to make some tags for your class, and then register SyntaxReceiver to walk around the tree to find the tags to achieve recording and filtering. See the example of attribute notification for details.

Note: SourceGeneratorContext will be renamed GeneratorExecutionContext in subsequent new versions.

Here I will describe the official recommendation process. Newbies will definitely be confused if they don’t understand this:

1) Implement the OnVisitSyntaxNode method of ISyntaxReceiver.

2) Write your demo and press F5 / F6 to generate it;

3) The code you write is instantly translated into a syntax tree. The compiler immediately traverses the syntax tree and enters the OnVisitSyntaxNode method one node at a time. The nodes that satisfy your taste are recorded.

4) The Recevier carries the selected node, is loaded into the context SourceGeneratorContext and enters the Execute method of the ISourceGenerator interface. At this time, the information in your Recevier is all the information that meets the conditions. Even if you obtain the class node, it is still a bunch of class nodes. , which requires manual processing and differentiation.

The process recommended by the author:

Do not write the classes you want to modify into .cs files, because the current source code generation technology does not allow you to modify existing classes. It is not allowed or supported. There is no such thing as syntax tree replacement. It allows you to add source code and operate some categories, but it does not allow you to modify the existing cs file.

I personally recommend customizing the template and letting the SG project parse the template and then add it to your project without delaying use or reference. However, for the ecology, there must be unified normative constraints.

c2b0a9f6942aeb7e260d6c32bf306bb9.png

After generating via SG:

public UseMethodModel Show3(ref int a, out string b)
{
       UseMethodModelAopProxy.BeforeShow3?.Invoke(this,ref a,out b);


       Console.WriteLine("In Show3()");
       b = "b";
       
       UseMethodModelAopProxy.AfterShow3?.Invoke(this,ref a,out b);
       return this;


}

The following is the usage code of AOP:

The current example incorporates Natasha to enable runtime dynamic script assignment.

f0c08c8886cf8345f6ac424e08fbd29d.png

operation result

77061d16de83c7dd007c75203e30834c.png

3. Does the change take effect?

VS daily metaphysical operations, right-click to clean, and clean both projects. Just run again.

4. Still not working, it became popular.

It happens during compilation. Do you want to try compiling it? After running through, turn off VS, and then turn it back on and everything will be green.

Run away, but it still doesn’t work?

It may be that the SG project caused an exception, please check it yourself.

5. Not able to operate syntax trees.

You can refer to this project. If someone participates in the maintenance, it will be released: https://github.com/dotnet-lab/Papper. If not, just quote it locally.

6. Packaged for use?

<ItemGroup>
    <!-- Package the generator in the analyzer directory of the nuget package -->
    <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>

6e3b15aa25050e46da15324055c41d87.png

Use GeneratePathProperty = true to generate the Pkg variable of the corresponding package, and then output it.

b5b0c84f0839bf44f6687e8cd6db8166.png

I haven’t written a demo of templates and annotations yet. Forgive me for not having much energy and time to devote to this matter, but after going through the AOP project, I can be sure that these two functions can be realized. The above questions have covered most of the pitfalls of early adopters. You can give it a try. Objectively speaking, the API is still changing, and various supernatural events have occurred in VS during experiments (currently, my VS has sequelae) and the official The impact of technology on ecology is still a wait-and-see attitude, so I suggest that you be patient and not impatient. You can customize plans and conduct experimental research, but you should still be cautious when it comes to production! ! Finally, remember to like and take a look.

eeaa65b8f20a954fe70e7ac8ba5c3dfa.png

Nothing, let’s break up the meeting!

https://github.com/dotnetcoreb4b71abcb25d09653c4c63c51afe71af.gif

A glass of wine will reduce your worries.
Follow us, you have the hair loss package.

996cd5645046b77cbbb882bba13cb07e.png

87caddae29dffac6dfce3327ca7e914f.jpeg

If the organization’s reward account is a lemon account, please mark “NCC” and leave your name. The income and expenditure details can be viewed at the following address: https://github.com/dotnetcore/Home/blob/master/Statement-of- Income-and-Expense.md55527a3215545c9f35592a96db02673a .pngd35de371f68910ba56890d5e00dafc64.png

OpenNCC, a public account focusing on .NET technology

https://www.dotnetcore.xyz

0c4229d051d6a83a859a3ccd853d8881.png

9fb4cf5b7607b831f09e32070095672c.pngWeChat ID: OpenNCC

\ Long press the left two -dimensional code to follow

Welcome tipping organizations

Give us more support

93879b248f392c2bd4ab1d15ce100fae.png