<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.0">Jekyll</generator><link href="https://jaylee.org/rss" rel="self" type="application/atom+xml" /><link href="https://jaylee.org/" rel="alternate" type="text/html" /><updated>2020-10-11T03:02:26+00:00</updated><id>https://jaylee.org/rss</id><title type="html">Jerome Laban’s Blog</title><subtitle>My name is Jérôme Laban, I'm a Software Architect from Montreal, working on mostly .NET and C#, with Windows, Xamarin and WebAssembly. I'm the CTO of the open source Uno Platform. MVP 2009-2011;2020</subtitle><entry><title type="html">How to profile C# 9.0 Source Generators</title><link href="https://jaylee.org/archive/2020/10/10/profiling-csharp-9-source-generators.html" rel="alternate" type="text/html" title="How to profile C# 9.0 Source Generators" /><published>2020-10-10T05:00:00+00:00</published><updated>2020-10-10T05:00:00+00:00</updated><id>https://jaylee.org/archive/2020/10/10/profiling-csharp-9-source-generators</id><content type="html" xml:base="https://jaylee.org/archive/2020/10/10/profiling-csharp-9-source-generators.html">&lt;p&gt;C# 9.0 source generators are progressing a lot lately, with the addition of generated symbols IDE navigation, as well as the stabilization of the generation APIs.&lt;/p&gt;

&lt;p&gt;As generators are run a part of the compiler’s pipeline, when &lt;a href=&quot;https://jaylee.org/archive/2020/04/29/notify-property-changed-with-rosyln-generators.html&quot;&gt;creating small generators&lt;/a&gt;, or processing small inputs, performance profiling can be done quite easily, and even easier using &lt;a href=&quot;https://github.com/chsienki/kittitas&quot;&gt;Chris Sienkiewicz’s kittitas tool&lt;/a&gt;, which packages the generation driver inside a single, easy to use tool.&lt;/p&gt;

&lt;p&gt;Yet, when the build is more complex, or the solution takes an important environmental set of parameters (such as &lt;a href=&quot;https://docs.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2019&quot;&gt;Directory.Build.props&lt;/a&gt;), some in-place debugging may be required.&lt;/p&gt;

&lt;p&gt;Read on to find out how to do this.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;in-place-profiling-of-source-generators-using-visual-studio&quot;&gt;In-Place Profiling of Source Generators using Visual Studio&lt;/h2&gt;

&lt;p&gt;While debugging the Uno source generators’ migration to C# 9.0, I found out that the generation was taking quite a while, particularly at the last stage of the many-projects solution that builds Uno itself.&lt;/p&gt;

&lt;p&gt;As the generators are part of the build pipeline, one way to profile the generators is to actually profile the invocation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;csc.exe&lt;/code&gt; itself. Note that you can debug your generators using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Debugger.Launch()&lt;/code&gt; technique (Nick has a &lt;a href=&quot;https://nicksnettravels.builttoroam.com/debug-code-gen/&quot;&gt;great blog entry&lt;/a&gt; about this).&lt;/p&gt;

&lt;p&gt;To profile your generators, first you’ll need to :&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Install the Visual Studio &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.ProjectSystemTools&quot;&gt;Project System Tools&lt;/a&gt;. Those tools enable the generation of msbuild binlog files from within Visual Studio. Binlogs are even created for design time builds, a nice touch.&lt;/li&gt;
  &lt;li&gt;Install the amazing &lt;a href=&quot;https://msbuildlog.com/&quot;&gt;MSBuild Binary and Structured Log Viewer&lt;/a&gt;, an amazing tool by Kirill Osenkov. You may need to open it once for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.binlog&lt;/code&gt; extension to be registered.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, you’ll need to do the following:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;In the &lt;strong&gt;Tools&lt;/strong&gt; menu, &lt;strong&gt;Options&lt;/strong&gt;, go to &lt;strong&gt;Project and Solutions&lt;/strong&gt;, &lt;strong&gt;Build and Run&lt;/strong&gt;, then select &lt;strong&gt;Diagnostics&lt;/strong&gt; in the &lt;strong&gt;MSBuild project build log verbosity&lt;/strong&gt; options.&lt;/li&gt;
  &lt;li&gt;Go to the &lt;strong&gt;View&lt;/strong&gt;, &lt;strong&gt;Other Windows&lt;/strong&gt;, &lt;strong&gt;Build Logging menu&lt;/strong&gt; to open the &lt;strong&gt;Build Logging&lt;/strong&gt; tool window&lt;/li&gt;
  &lt;li&gt;In that &lt;strong&gt;Build Logging&lt;/strong&gt; window, click on the &lt;strong&gt;Play&lt;/strong&gt; icon to start the logging&lt;/li&gt;
  &lt;li&gt;Build your project which uses the source generators&lt;/li&gt;
  &lt;li&gt;Once built, in the &lt;strong&gt;Build Logging&lt;/strong&gt; window, select the line that contains your project’s build results, and right click &lt;strong&gt;Open Logs External&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;In the top left text box, type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;csc.exe&lt;/code&gt;, you’ll find the actual command line visual studio used to build the code from your project, including the generators’ execution.&lt;/li&gt;
  &lt;li&gt;In tree view on the left, click on the line &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Property CommandLineArguments = ...&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;On the right, the full line is selected and right click to &lt;strong&gt;Copy Value&lt;/strong&gt;
&lt;img src=&quot;/assets/images/20201010-generators-profiling-binlog.png&quot; alt=&quot;copy the csc arguments&quot; /&gt;&lt;/li&gt;
  &lt;li&gt;Paste the content in your favorite text editor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let’s configure your generators project to be profiled:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Set your generators project as startup in the solution explorer&lt;/li&gt;
  &lt;li&gt;Open the generators &lt;strong&gt;project properties&lt;/strong&gt;, and the &lt;strong&gt;Debug&lt;/strong&gt; tab&lt;/li&gt;
  &lt;li&gt;Take the path to your csc.exe in the file created above, and set it to the &lt;strong&gt;Executable&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Set the &lt;strong&gt;Working directory&lt;/strong&gt; to the folder containing the project that was previously built&lt;/li&gt;
  &lt;li&gt;Save the file created with the compiler options, while removing the path to csc.exe, leaving only the command line parameters. This file can be anywhere, let’s say &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Temp\myresponsefile.rsp&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;In the &lt;strong&gt;Application arguments&lt;/strong&gt;, set the following:
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  @C:\Temp\myresponsefile.rsp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;This will instruct the compiler to take its command line parameters from &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/response-file-compiler-option&quot;&gt;the response file&lt;/a&gt; we created.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Go to the &lt;strong&gt;Debug&lt;/strong&gt;, &lt;strong&gt;Performance Profiler&lt;/strong&gt; menu, select &lt;strong&gt;CPU Usage&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Click &lt;strong&gt;Start&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And voila!&lt;/p&gt;

&lt;p&gt;It’s not the simplest of steps, but it works pretty nicely.&lt;/p&gt;

&lt;p&gt;Note that the response file is not strictly necessary, but if your project has lots of files (which is the case for the Uno.UI solution), the &lt;strong&gt;Application arguments&lt;/strong&gt; field is characters limited and may not work properly.&lt;/p&gt;

&lt;h2 id=&quot;in-closing&quot;&gt;In closing&lt;/h2&gt;

&lt;p&gt;In the context of debugging Uno’s generators, here’s what came out:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/20201010-generators-profiling.png&quot; alt=&quot;profiling output&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Indicating that the generators are spending a &lt;em&gt;lot&lt;/em&gt; of time generating the names of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ISymbol&lt;/code&gt; instances.&lt;/p&gt;

&lt;p&gt;Looks like we’re going to have a good time improving the performance of Uno’s source generators!&lt;/p&gt;

&lt;p&gt;Until next time, happy generation!&lt;/p&gt;</content><author><name>Jerome</name></author><category term="Archive" /><category term=".NET" /><category term="C#" /><category term="Source Generation" /><category term="Roslyn" /><category term="msbuild" /><summary type="html">C# 9.0 source generators are progressing a lot lately, with the addition of generated symbols IDE navigation, as well as the stabilization of the generation APIs. As generators are run a part of the compiler’s pipeline, when creating small generators, or processing small inputs, performance profiling can be done quite easily, and even easier using Chris Sienkiewicz’s kittitas tool, which packages the generation driver inside a single, easy to use tool. Yet, when the build is more complex, or the solution takes an important environmental set of parameters (such as Directory.Build.props), some in-place debugging may be required. Read on to find out how to do this.</summary></entry><entry><title type="html">Using MSBuild Items and Properties in C# 9 Source Generators</title><link href="https://jaylee.org/archive/2020/09/13/msbuild-items-and-properties-in-csharp9-sourcegenerators.html" rel="alternate" type="text/html" title="Using MSBuild Items and Properties in C# 9 Source Generators" /><published>2020-09-13T05:00:00+00:00</published><updated>2020-09-13T05:00:00+00:00</updated><id>https://jaylee.org/archive/2020/09/13/msbuild-items-and-properties-in-csharp9-sourcegenerators</id><content type="html" xml:base="https://jaylee.org/archive/2020/09/13/msbuild-items-and-properties-in-csharp9-sourcegenerators.html">&lt;p&gt;C# 9.0 Source Generation is &lt;a href=&quot;https://twitter.com/jaredpar/status/1301315173244788736&quot;&gt;progressing quite nicely lately&lt;/a&gt; (Thanks, Jared!), with the addition of the ability to interact with the MSBuild environment such as getting Properties and Items to control how the generation happens.&lt;/p&gt;

&lt;p&gt;In this post, I’ll explain how to parse &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.resw&lt;/code&gt; files of a project to generate an enum that contains all the resources.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;The full sample for this article is &lt;a href=&quot;https://github.com/jeromelaban/fonderie&quot;&gt;here in the Fonderie Generators project&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;reading-msbuild-items-and-properties&quot;&gt;Reading msbuild items and properties&lt;/h2&gt;

&lt;p&gt;In the &lt;a href=&quot;https://github.com/dotnet/roslyn/blob/master/docs/features/source-generators.cookbook.md&quot;&gt;Roslyn generators cookbook&lt;/a&gt;, new entries have been added to include the APIs needed to get information from msbuild. In order to make the reading of those properties easier, here’s a small extensions class:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;internal&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SourceGeneratorContextExtensions&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SourceItemGroupMetadata&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;build_metadata.AdditionalFiles.SourceItemGroup&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetMSBuildProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SourceGeneratorContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultValue&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnalyzerConfigOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GlobalOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TryGetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;build_property.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetMSBuildItems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SourceGeneratorContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AdditionalFiles&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnalyzerConfigOptions&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TryGetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SourceItemGroupMetadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;out&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sourceItemGroup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sourceItemGroup&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s dive into what those extensions do.&lt;/p&gt;

&lt;h3 id=&quot;getmsbuildproperty&quot;&gt;GetMSBuildProperty&lt;/h3&gt;
&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetMSBuildProperty&lt;/code&gt; method is assuming that a defined property has a non-empty value, as per the msbuild semantics. Here’s how to get the default namespace for the current project:&lt;/p&gt;
&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defineConstants&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetMSBuildProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RootNamespace&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Assuming that the associated msbuild property is added in the generator’s associated props file:&lt;/p&gt;
&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;CompilerVisibleProperty&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RootNamespace&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;getmsbuilditems&quot;&gt;GetMSBuildItems&lt;/h3&gt;
&lt;p&gt;For &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetMSBuildItems&lt;/code&gt;, since the roslyn APIs does not provide a way to discriminate items per their MSBuild item name, we need to use some metadata that can be added to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AdditionalFiles&lt;/code&gt; items. In order to get the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resw&lt;/code&gt; files from a WinUI project, we can do the following:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;priResources&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetMSBuildItems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PRIResource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For this code to work, we need to change a little bit the way items are added to the roslyn context:&lt;/p&gt;
&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Target&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;_InjectAdditionalFiles&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;BeforeTargets=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;GenerateMSBuildEditorConfigFileShouldRun&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;AdditionalFiles&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;@(PRIResource)&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;SourceItemGroup=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PRIResource&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Target&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The use of a target here is needed because of the way NuGet packages property or targets files are handled by msbuild. If the ItemGroup is included directly at the root of the project, its evaluation is performed too early in the build process. This sequence misses items being added by the project or dynamically by other targets.&lt;/p&gt;

&lt;p&gt;At this point, there’s no clear injection point to execute this targe in Roslyn, but &lt;a href=&quot;https://github.com/dotnet/roslyn/blob/ff854c695779990b9b269029a8615782a59ec530/src/Compilers/Core/MSBuildTask/Microsoft.Managed.Core.targets#L112&quot;&gt;GenerateMSBuildEditorConfigFileShouldRun&lt;/a&gt; seems like an appropriate location for doing so at this point, right before the capture of the properties and items by the build.&lt;/p&gt;

&lt;p&gt;Finally, to be able to discriminate items in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AdditionalFiles&lt;/code&gt; group, we use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SourceItemGroup&lt;/code&gt; metadata. For Roslyn to pick it up, we need to add the following:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;CompilerVisibleItemMetadata&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;AdditionalFiles&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;MetadataName=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;SourceItemGroup&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;generating-code-from-the-resw-file&quot;&gt;Generating code from the resw file&lt;/h2&gt;

&lt;p&gt;Now that we can read the items and properties, we can write a small generator that creates an enum with all the names found in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resw&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ReswConstantsGenerator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ISourceGenerator&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InitializationContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Debugger.Launch(); // Uncomment this line for debugging&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// No initialization required for this one&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SourceGeneratorContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resources&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetMSBuildItems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PRIResource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IndentedStringBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BlockInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;namespace &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetMSBuildProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;RootNamespace&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BlockInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;internal enum PriResources&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;XmlDocument&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;XmlDocument&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

                        &lt;span class=&quot;c1&quot;&gt;// Extract all localization keys from Win10 resource file&lt;/span&gt;
                        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nodes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;SelectNodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;//data&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Cast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;XmlElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;()&lt;/span&gt;
                            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

                        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AppendLineInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;,&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddSource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;PriResources&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SourceText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;From&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UTF8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will generate a file which contains an enum with all the resource names, in the default namespace of the current assembly.&lt;/p&gt;

&lt;p&gt;Note that this generator does not validate the name’s format, and if there are reserved characters or keywords, those are needed to be rewritten for C# to accept it.&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;This simple sample should most likely be improved.&lt;/p&gt;

&lt;p&gt;For instance, it could be interesting to create a generator analyzing another generator to create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.targets&lt;/code&gt; file which contains the appropriate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompilerVisibleItemMetadata&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CompilerVisibleProperty&lt;/code&gt; for that generator to work properly.&lt;/p&gt;

&lt;p&gt;The extension also only supports getting the identity of an item, but getting additional metadata would be useful, like getting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Link&lt;/code&gt; attribute when dealing with linked files in projects.&lt;/p&gt;

&lt;p&gt;You can find the &lt;a href=&quot;https://github.com/jeromelaban/fonderie&quot;&gt;sample of this article here&lt;/a&gt;, and as of the writing of this post, Visual Studio 16.8 Preview 2.1 does not yet show the generated code or highlights properly but builds with the generated code properly. This should be improving the next previews.&lt;/p&gt;

&lt;p&gt;Until next time, happy generation!&lt;/p&gt;</content><author><name>Jerome</name></author><category term="Archive" /><category term=".NET" /><category term="C#" /><category term="Source Generation" /><category term="Roslyn" /><summary type="html">C# 9.0 Source Generation is progressing quite nicely lately (Thanks, Jared!), with the addition of the ability to interact with the MSBuild environment such as getting Properties and Items to control how the generation happens. In this post, I’ll explain how to parse .resw files of a project to generate an enum that contains all the resources.</summary></entry><entry><title type="html">How to get the SyntaxNode of an ISymbol using Roslyn</title><link href="https://jaylee.org/archive/2020/07/19/how-to-get-the-syntaxnode-for-a-symbol-using-roslyn.html" rel="alternate" type="text/html" title="How to get the SyntaxNode of an ISymbol using Roslyn" /><published>2020-07-19T05:00:00+00:00</published><updated>2020-07-19T05:00:00+00:00</updated><id>https://jaylee.org/archive/2020/07/19/how-to-get-the-syntaxnode-for-a-symbol-using-roslyn</id><content type="html" xml:base="https://jaylee.org/archive/2020/07/19/how-to-get-the-syntaxnode-for-a-symbol-using-roslyn.html">&lt;p&gt;In this post, I’ll describe how to determine if a property is an auto-property, using its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ISymbol&lt;/code&gt; as the source, and not by using reflection into Roslyn which computes this information internally.&lt;/p&gt;

&lt;p&gt;During the original development of the &lt;a href=&quot;https://github.com/unoplatform/Uno.CodeGen/&quot;&gt;Uno CodeGen source generators&lt;/a&gt;, when building the &lt;a href=&quot;https://github.com/unoplatform/Uno.CodeGen#create-truly-immutable-entities-in-c&quot;&gt;Immutable generators&lt;/a&gt; (soon to be deprecated by the &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/&quot;&gt;records feature in C# 9.0&lt;/a&gt;), we had to determine &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties&quot;&gt;if a property’s backing field is generated or not&lt;/a&gt;.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;At the time, not understanding fully the Roslyn sources, and with lack of time, we chose to go the easy and hacky route (with reflection on internal members). And like any hacky route, it always come back at your one way or another. In Roslyn 3.6, internals have changed breaking that reflection based code.&lt;/p&gt;

&lt;p&gt;Still, we knew that it was going to break in the future so the &lt;a href=&quot;https://github.com/unoplatform/Uno.CodeGen/blob/0bdde7524c34346c4115e074c89c1585dfa74217/src/Uno.CodeGen/Helpers/TypeSymbolExtensions.cs#L368-L369&quot;&gt;error message was very explicit&lt;/a&gt; in saying that we were looking for something internal that could not be found.&lt;/p&gt;

&lt;h2 id=&quot;how-determine-if-a-property-is-an-auto-property&quot;&gt;How determine if a property is an auto-property&lt;/h2&gt;

&lt;p&gt;Given an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IPropertySymbol&lt;/code&gt;, it’s possible to get the location of the definition:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;symbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Locations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FirstOrDefault&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If a symbol has no location, it generally means it’s defined outside the current compilation (e.g. in a referenced assembly).&lt;/p&gt;

&lt;p&gt;Then we can get the actual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SyntaxNode&lt;/code&gt; of that location:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SourceTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetRoot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()?.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FindNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SourceSpan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FindNode&lt;/code&gt; method uses the location’s source span to lookup the appropriate so it can be traversed and analyzed syntactically. Note that there may not be a SourceTree for the that location either.&lt;/p&gt;

&lt;p&gt;Once we have the node, we can analyze it:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isExplicitProperty&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DescendantNodesAndSelf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OfType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PropertyDeclarationSyntax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AccessorList&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AccessorList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Accessors&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExpressionBody&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// readonly arrow property declaration&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s what happens:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;The code take only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PropertyDeclarationSyntax&lt;/code&gt; nodes&lt;/li&gt;
  &lt;li&gt;Determine if there’s an accessor list (are there explicit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set&lt;/code&gt; keywords)&lt;/li&gt;
  &lt;li&gt;Then if there are accessors, determine if they have a body (with curly braces) or are using the arrow syntax (lambda properties).&lt;/li&gt;
  &lt;li&gt;If there are no accessors, this means it’s a readonly property with an arrow syntax.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this, you can know if a property is an auto-property or not.&lt;/p&gt;

&lt;p&gt;This code is based on the &lt;a href=&quot;https://github.com/dotnet/roslyn/blob/ba014d9d7728de0d4b5df3859507f9701e7032c0/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs#L205&quot;&gt;actual roslyn source code&lt;/a&gt; for the internal IsAutoProperty property.&lt;/p&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;This code is not future proof, though. Even if it’s not using internal APIs, the language will evolve and may add newer features that may break or ignore newer constructs that will appear in later versions of the language.&lt;/p&gt;

&lt;p&gt;That will be the topic of a future post, if that happens :)&lt;/p&gt;</content><author><name>Jerome</name></author><category term="Archive" /><category term=".NET" /><category term="C#" /><category term="Source Generation" /><category term="Roslyn" /><summary type="html">In this post, I’ll describe how to determine if a property is an auto-property, using its ISymbol as the source, and not by using reflection into Roslyn which computes this information internally. During the original development of the Uno CodeGen source generators, when building the Immutable generators (soon to be deprecated by the records feature in C# 9.0), we had to determine if a property’s backing field is generated or not.</summary></entry><entry><title type="html">INotifyPropertyChanged with C# 9.0 Source Generators</title><link href="https://jaylee.org/archive/2020/04/29/notify-property-changed-with-rosyln-generators.html" rel="alternate" type="text/html" title="INotifyPropertyChanged with C# 9.0 Source Generators" /><published>2020-04-29T05:00:00+00:00</published><updated>2020-04-29T05:00:00+00:00</updated><id>https://jaylee.org/archive/2020/04/29/notify-property-changed-with-rosyln-generators</id><content type="html" xml:base="https://jaylee.org/archive/2020/04/29/notify-property-changed-with-rosyln-generators.html">&lt;p&gt;In a design meeting far, far away, source generators were &lt;a href=&quot;https://github.com/dotnet/roslyn/blob/12bd769ebcd3121b88f535e8559f5a42d9c0e873/docs/features/generators.md&quot;&gt;designed to be part of C# 6.0&lt;/a&gt;, but sadly never came to be. At the time, wanting that source generation feature pretty badly, I went on implementing the specification which later became &lt;a href=&quot;https://github.com/unoplatform/Uno.SourceGeneration&quot;&gt;Uno.SourceGeneration&lt;/a&gt;, and it turns out it was the right decision to stick with a very similar API.&lt;/p&gt;

&lt;p&gt;I could port the &lt;a href=&quot;https://jaylee.org/archive/2019/12/08/roslyn-sourcegeneration-reborn-replace-inotifypropertychanged.html&quot;&gt;INotifyPropertyChanged (INPC) generator I built a while back&lt;/a&gt; that uses &lt;a href=&quot;https://github.com/unoplatform/Uno.SourceGeneration&quot;&gt;Uno.SourceGeneration&lt;/a&gt; package, convert it to use Roslyn’s &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/&quot;&gt;shiny new C# 9.0 feature&lt;/a&gt; in a matter of minutes. Amazing!&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;the-inpc-generator&quot;&gt;The INPC Generator&lt;/h2&gt;

&lt;p&gt;As a quick refresher, the generator works by allowing the creation of a class this way:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;partial&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyClass&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GeneratedProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_myProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;partial&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnMyPropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;previousValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;OnMyPropertyChanged(&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;previousValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’ll notice here that the property is not visible at all, and it will be assumed that the generator will recognize the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GeneratedPropertyAttribute&lt;/code&gt; and do the rest of the work for the author of the class.&lt;/p&gt;

&lt;p&gt;The generator could then produce something like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;partial&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyClass&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INotifyPropertyChanged&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyProperty&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_myProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;previous&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_myProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;_myProperty&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;PropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Invoke&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;PropertyChangedEventArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)));&lt;/span&gt;
      &lt;span class=&quot;nf&quot;&gt;OnMyPropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;previous&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;partial&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnMyPropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;previousValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This generator is generating the property on your behalf, and automatically implements the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INotifyPropertyChanged&lt;/code&gt; as well as a partial method that you can optionally implement to get local notification on changes.&lt;/p&gt;

&lt;p&gt;For a more detailed explanation of the generation process, &lt;a href=&quot;https://jaylee.org/archive/2019/12/08/roslyn-sourcegeneration-reborn-replace-inotifypropertychanged.html&quot;&gt;head to this earlier article&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;upgrading-the-source-generator-to-c-90&quot;&gt;Upgrading the source generator to C# 9.0&lt;/h2&gt;

&lt;p&gt;First, we’ll need the &lt;a href=&quot;https://github.com/jeromelaban/inpc.generator&quot;&gt;INPC.Generator Sample Project&lt;/a&gt; to use the the C# 9.0 preview:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;LangVersion&amp;gt;&lt;/span&gt;preview&lt;span class=&quot;nt&quot;&gt;&amp;lt;/LangVersion&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then change the NuGet packages from Uno.SourceGeneration to Roslyn’s Analyzers:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Microsoft.CodeAnalysis.CSharp.Workspaces&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;3.6.0-3.20207.2&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;PrivateAssets=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;all&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Microsoft.CodeAnalysis.Analyzers&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;3.0.0-beta2.final&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;PrivateAssets=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;all&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then we’ll need to adjust the source code to be use the new interfaces:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MySourceGenerator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ISourceGenerator&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InitializationContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// No initialization required for this one&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SourceGeneratorContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Generation&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The execute method in Uno.SourceGeneration has the same signature, and the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SourceGeneratorContext&lt;/code&gt; type the only property that really matters &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Compilation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The method to provide the generated source has changed a bit, and uses a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SourceText&lt;/code&gt; instead of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddSource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sanitizedName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SourceText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;From&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UTF8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’ll need to update the path to the binary, where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SourceGenerator&lt;/code&gt; becomes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Analyzer&lt;/code&gt;, in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INPC.Generator.props&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;Analyzer&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;$(MSBuildThisFileDirectory)..\bin\$(Configuration)\netstandard2.0\INPC.Generator.dll&quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;Condition=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Exists('$(MSBuildThisFileDirectory)..\bin')&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;Analyzer&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;$(MSBuildThisFileDirectory)..\tools\INPC.Generator.dll&quot;&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;Condition=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Exists('$(MSBuildThisFileDirectory)..\tools')&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And finally, we simply need to compile the main program with the C# 9.0 preview.&lt;/p&gt;

&lt;p&gt;When running the sample, here’s what happens:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;OnIntPropertyChanged(0,42)
OnIntPropertyChanged(,My 42)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The job is done!&lt;/p&gt;

&lt;h2 id=&quot;in-closing&quot;&gt;In closing&lt;/h2&gt;

&lt;p&gt;I hope the feature will grow, and provide lots more like access to msbuild properties, or &lt;a href=&quot;https://github.com/unoplatform/Uno.SourceGeneration#general-guidelines-for-creating-generators&quot;&gt;dependencies between generators&lt;/a&gt;, and it will &lt;a href=&quot;https://developercommunity.visualstudio.com/content/problem/588021/the-compile-itemgroup-intellisense-cache-is-not-re.html&quot;&gt;finally fix the issues with dynamically generated&lt;/a&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;Compile /&amp;gt;&lt;/code&gt; item groups.&lt;/p&gt;

&lt;p&gt;I hope you will give this feature a try, as it opens up a world of possibilities, as we’ve been finding out while developing Uno (Here’s the &lt;a href=&quot;https://github.com/unoplatform/uno/tree/master/src/SourceGenerators/Uno.UI.SourceGenerators&quot;&gt;list of generators&lt;/a&gt;), as well as the &lt;a href=&quot;https://github.com/unoplatform/Uno.CodeGen&quot;&gt;Uno.CodeGen generators&lt;/a&gt; (which some may not be needed anymore with the C# 9.0 records feature!).&lt;/p&gt;

&lt;p&gt;Happy source-generation!&lt;/p&gt;</content><author><name>Jerome</name></author><category term="Archive" /><category term=".NET" /><category term="C#" /><category term="Source Generation" /><category term="Roslyn" /><summary type="html">In a design meeting far, far away, source generators were designed to be part of C# 6.0, but sadly never came to be. At the time, wanting that source generation feature pretty badly, I went on implementing the specification which later became Uno.SourceGeneration, and it turns out it was the right decision to stick with a very similar API. I could port the INotifyPropertyChanged (INPC) generator I built a while back that uses Uno.SourceGeneration package, convert it to use Roslyn’s shiny new C# 9.0 feature in a matter of minutes. Amazing!</summary></entry><entry><title type="html">C# interop with C/C++ and Rust in WebAssembly</title><link href="https://jaylee.org/archive/2020/03/22/csharp-interop-with-c-cpp-and-rust-in-webassembly.html" rel="alternate" type="text/html" title="C# interop with C/C++ and Rust in WebAssembly" /><published>2020-03-22T05:00:00+00:00</published><updated>2020-03-22T05:00:00+00:00</updated><id>https://jaylee.org/archive/2020/03/22/csharp-interop-with-c-cpp-and-rust-in-webassembly</id><content type="html" xml:base="https://jaylee.org/archive/2020/03/22/csharp-interop-with-c-cpp-and-rust-in-webassembly.html">&lt;p&gt;Having the ability to call code written in other languages is increasingly important, as there are many very useful libraries that are getting ported over to WebAssembly. In .NET, the common defined way for doing interop is &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke&quot;&gt;P/Invoke and DllImport&lt;/a&gt;, and .NET for WebAssembly has support for it in the form of static linking of LLVM Bitcode object files.&lt;/p&gt;

&lt;p&gt;In this article, I will walk through how to call some simple C/C++ and Rust code from C# in a WebAssembly app.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;In the general .NET sense, P/Invoke was built to perform dynamic linking with Windows PE Dlls, but has been extended in mono to allow for static linking. This technique is also &lt;a href=&quot;https://github.com/mono/SkiaSharp/blob/d16fd524b0e4c8715fc89abaca3ccfd6fb103b93/binding/Binding/SkiaApi.cs#L10&quot;&gt;used by mono on iOS to call native code&lt;/a&gt;, and allows for a single executable package to contain the code to execute the application. This is what is used for the demos in this article.&lt;/p&gt;

&lt;h2 id=&quot;setting-up-the-c-webassembly-project&quot;&gt;Setting up the C# WebAssembly project&lt;/h2&gt;

&lt;p&gt;First let’s create create a .NET WebAssembly app, using the &lt;a href=&quot;https://github.com/unoplatform/Uno.Wasm.Bootstrap&quot;&gt;Uno WebAssembly Bootstrapper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note that macOS is not yet supported for the static linking scenario, and that on Windows 10 you’ll need to have &lt;a href=&quot;https://platform.uno/blog/build-net-aot-for-webassembly-in-visual-studio-with-uno-platform&quot;&gt;WSL installed&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Create a .NET Standard 2.0 Library in Visual Studio for Windows or using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dotnet new classlib&lt;/code&gt; under linux.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Replace the content of the project with the following:&lt;/p&gt;

    &lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nt&quot;&gt;&amp;lt;Project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Sdk=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Microsoft.NET.Sdk.Web&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;nt&quot;&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;OutputType&amp;gt;&lt;/span&gt;Exe&lt;span class=&quot;nt&quot;&gt;&amp;lt;/OutputType&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;netstandard2.0&lt;span class=&quot;nt&quot;&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;MonoRuntimeDebuggerEnabled&amp;gt;&lt;/span&gt;false&lt;span class=&quot;nt&quot;&gt;&amp;lt;/MonoRuntimeDebuggerEnabled&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;WasmShellMonoRuntimeExecutionMode&amp;gt;&lt;/span&gt;InterpreterAndAOT&lt;span class=&quot;nt&quot;&gt;&amp;lt;/WasmShellMonoRuntimeExecutionMode&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Uno.Wasm.Bootstrap&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.1.0-dev.426&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;DotNetCliToolReference&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Uno.Wasm.Bootstrap.Cli&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.1.0-dev.426&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- This automatically includes any Bitcode file for static linking --&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;Content&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;*.bc&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Create a file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Program.cs&lt;/code&gt;
    &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;MyApp&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Program&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Build the app once. This will download the .NET WebAssembly SDK, and install emscripten for the app.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;build-a-cc-library&quot;&gt;Build a C/C++ library&lt;/h2&gt;

&lt;p&gt;To build a C/C++ library, we’ll need to create a simple file that contains an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extern &quot;C&quot;&lt;/code&gt; exported function, in order to have a signature and calling convention that can be used properly with .NET P/Invoke.&lt;/p&gt;

&lt;p&gt;In the WebAssembly app, let’s create a folder named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;myclib&lt;/code&gt; and add a file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mylib.cpp&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-cpp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;stdio.h&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cpp_add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Save the file, and open a bash or WSL window.&lt;/p&gt;

&lt;p&gt;We can go the path containing the file using the great &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wslpath&lt;/code&gt; tool:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;wslpath &lt;span class=&quot;s2&quot;&gt;&quot;C:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\Y&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ourPathToYourProject&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\m&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;yclib&quot;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We’ll need to initialize emscripten:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt; ../obj/emsdk-&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/emsdk/emsdk_env.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then build the library:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;emcc mylib.cpp &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; ../myclib.bc &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;WASM&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At this point, we’ve generated a Bitcode file that can be used by the .NET tool chain, and for which an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extern &quot;C&quot;&lt;/code&gt; marked function can be called from C#.&lt;/p&gt;

&lt;h2 id=&quot;call-the-c-function-from-c&quot;&gt;Call the C++ function from C#&lt;/h2&gt;

&lt;p&gt;Now that we have our library built, we can update our C# program to make the C++ function callable:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Runtime.InteropServices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Program&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DllImport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;myclib&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cpp_add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;cpp_add: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cpp_add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When building the app, and running it, this will appear in the browser’s console:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cpp_add: 42
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;build-a-rust-static-library&quot;&gt;Build a Rust static library&lt;/h2&gt;

&lt;p&gt;Following a similar path, to build a Rust static library we’ll need to create a simple file that contains a function marked with the &lt;a href=&quot;https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#[export_name]&lt;/code&gt; attribute&lt;/a&gt;, so that it can be found via P/Invoke.&lt;/p&gt;

&lt;p&gt;In the WebAssembly app, let’s create a folder named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;myrustlib&lt;/code&gt; and add a file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mylib.rs&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tests&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;#[export_name&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;rust_add&quot;&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rust_add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;u32&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Save the file, and open a bash window.&lt;/p&gt;

&lt;p&gt;Let’s &lt;a href=&quot;https://www.rust-lang.org/tools/install&quot;&gt;setup Rust&lt;/a&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rustup&lt;/code&gt; and add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cargo&lt;/code&gt; to your path:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl https://sh.rustup.rs &lt;span class=&quot;nt&quot;&gt;-sSf&lt;/span&gt; | sh
&lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;:&lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;/.cargo/bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then setup WebAssembly support for Rust:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rustup &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;stable
rustup default stable
rustup target add wasm32-unknown-emscripten
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’ll need to initialize emscripten here as well, if not done previously:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt; ../obj/emsdk-&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;/emsdk/emsdk_env.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can go the path containing the file:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;wslpath &lt;span class=&quot;s2&quot;&gt;&quot;C:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\Y&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ourPathToYourProject&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\m&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;yrustlib&quot;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then build the library&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rustc &lt;span class=&quot;nt&quot;&gt;--target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;wasm32-unknown-emscripten mylib.rs &lt;span class=&quot;nt&quot;&gt;--crate-type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;staticlib &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; ../myrustlib.bc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In a similar way we’ve done this for C++, the Bitcode file is now available for the .NET tool chain to use. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;staticlib&lt;/code&gt; parameter is important as it forces the rust compiler to create a standalone library, with all its internal support code included.&lt;/p&gt;

&lt;h2 id=&quot;calling-the-c-function-from-c&quot;&gt;Calling the C++ function from C#&lt;/h2&gt;

&lt;p&gt;With the Rust library built, we can update our C# program to make the Rust function callable:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System.Runtime.InteropServices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Program&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DllImport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;myclib&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cpp_add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DllImport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;myrustlib&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rust_add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;cpp_add: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cpp_add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;rust_add: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rust_add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When building and run the app again, the following will appear in the browser’s console:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cpp_add: 42
rust_add: 43
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;current-set-of-restrictions-for-pinvoke&quot;&gt;Current set of restrictions for P/Invoke&lt;/h2&gt;

&lt;p&gt;Under the covers, mono is generating a table of methods marked DllImport, and &lt;a href=&quot;https://github.com/mono/mono/blob/7038b1a4261f86dac2fda4f3894f397bddf88f2c/mcs/tools/wasm-tuner/tuner.cs#L180-L183&quot;&gt;generates a set of callable methods&lt;/a&gt; from referenced external libraries.&lt;/p&gt;

&lt;p&gt;The runtime needs to do so in order to determine what to call. Once a library and function has been found, the runtime &lt;a href=&quot;https://github.com/mono/mono/blob/ac1a12f9971fc7ba4f8f675af020dc18fd9d35ee/mono/mini/wasm_m2n_invoke.g.h#L1021&quot;&gt;has to determine the signature of the function&lt;/a&gt; in a &lt;a href=&quot;https://github.com/mono/mono/blob/6c0bfdc3f3d5855d27628112a505ba01bdfc4584/mono/mini/m2n-gen.cs#L30&quot;&gt;pre-defined signatures list&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If the native function signature is not in the list, you may encounter the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CANNOT HANDLE COOKIE XXXX&lt;/code&gt; assertion &lt;a href=&quot;https://github.com/mono/mono/blob/ac1a12f9971fc7ba4f8f675af020dc18fd9d35ee/mono/mini/wasm_m2n_invoke.g.h#L1823&quot;&gt;defined here&lt;/a&gt;. If you’re facing this error, you may want to adjust your native function signature so it finds itself in the &lt;a href=&quot;https://github.com/mono/mono/blob/6c0bfdc3f3d5855d27628112a505ba01bdfc4584/mono/mini/m2n-gen.cs#L30&quot;&gt;pre-defined signatures list&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All of this is caused by the fact that, for security reasons, WebAssembly functions cannot be called with a set of parameters unknown at compile time; a technique the mono runtime has to use when calling functions through P/Invoke.&lt;/p&gt;

&lt;p&gt;If you’re wondering how to determine the cookie of a function, as an example this function:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;static extern int cpp_add(int a, int b);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;has the cookie &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;III&lt;/code&gt;, where the first character defines the return type.&lt;/p&gt;

&lt;p&gt;Another example with this function:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;static extern void OtherFunction(int a, double b, float c);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;will have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VIDF&lt;/code&gt; cookie.&lt;/p&gt;

&lt;h2 id=&quot;webassembly-validations&quot;&gt;WebAssembly validations&lt;/h2&gt;

&lt;p&gt;Along with the restrictions of the P/Invoke list, making sure that the signature of the function tagged in the C# with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DllImport&lt;/code&gt; matches the function defined in the other libraries. In case of a mismatch, browsers will raise an error such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RuntimeError: function signature mismatch&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;next-up&quot;&gt;Next up…&lt;/h2&gt;

&lt;p&gt;We’ll discuss how to use strings back and forth in both environments.&lt;/p&gt;</content><author><name>Jerome</name></author><category term="Archive" /><category term=".NET" /><category term="C#" /><category term="Interop" /><category term="Rust" /><category term="C" /><category term="C++" /><summary type="html">Having the ability to call code written in other languages is increasingly important, as there are many very useful libraries that are getting ported over to WebAssembly. In .NET, the common defined way for doing interop is P/Invoke and DllImport, and .NET for WebAssembly has support for it in the form of static linking of LLVM Bitcode object files. In this article, I will walk through how to call some simple C/C++ and Rust code from C# in a WebAssembly app.</summary></entry><entry><title type="html">.NET Threading and WebAssembly</title><link href="https://jaylee.org/archive/2020/02/29/wasm-threads.html" rel="alternate" type="text/html" title=".NET Threading and WebAssembly" /><published>2020-02-29T05:00:00+00:00</published><updated>2020-02-29T05:00:00+00:00</updated><id>https://jaylee.org/archive/2020/02/29/wasm-threads</id><content type="html" xml:base="https://jaylee.org/archive/2020/02/29/wasm-threads.html">&lt;p&gt;Threading, in general operating systems sense, is not something that the web has been able to use until very recently. The addition of &lt;a href=&quot;https://github.com/WebAssembly/threads&quot;&gt;Threads support in WebAssembly&lt;/a&gt;, and the activation of the threading support in Chrome opens up a whole new world of possibilities, including the use of Reactive Extensions (Rx.NET) or the Task Parallel Library (TPL).&lt;/p&gt;

&lt;p&gt;Let’s dive in, with some sample code.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;h2 id=&quot;a-bit-of-history&quot;&gt;A bit of history&lt;/h2&gt;

&lt;p&gt;The only technique that was available for actual local parallelization of work in the javascript land was to use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers&quot;&gt;WebWorkers&lt;/a&gt;. It’s technically not threading in the same sense known by out-of-browsers developers, as it does not provide the ability to share memory between WebWorkers. To synchronize work, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage&quot;&gt;messages&lt;/a&gt; are passed between workers and &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Worker/onmessage&quot;&gt;the main loop&lt;/a&gt;, which looks more like processes would exchange messages via IPC.&lt;/p&gt;

&lt;p&gt;This changed recently with the ability for javascript to create &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer&quot;&gt;shared array buffers&lt;/a&gt;, contiguous pieces of memory that can be both read and written from workers and the main loop. Those buffers can only be &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects#Indexed_collections&quot;&gt;mapped to primitive types&lt;/a&gt;, for which access and manipulated can be synchronized via &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics&quot;&gt;atomic operations&lt;/a&gt;. Atomics are also used to perform signalling between threads.&lt;/p&gt;

&lt;p&gt;Those buffers had been disabled for a while because of &lt;a href=&quot;https://meltdownattack.com/&quot;&gt;CPU attacks Spectre and Meltdown&lt;/a&gt;, but are now enabled by default in Chrome and the new Edge.&lt;/p&gt;

&lt;h2 id=&quot;threads-in-emscripten&quot;&gt;Threads in Emscripten&lt;/h2&gt;

&lt;p&gt;WebAssembly Threads are &lt;a href=&quot;https://emscripten.org/docs/porting/pthreads.html&quot;&gt;supported in Emscripten&lt;/a&gt; via the &lt;a href=&quot;https://en.wikipedia.org/wiki/POSIX_Threads&quot;&gt;pthreads library&lt;/a&gt; and are backed by WebWorkers.&lt;/p&gt;

&lt;p&gt;When threads are created, new WebWorkers are created and &lt;a href=&quot;https://github.com/emscripten-core/emscripten/blob/4bd0bc3817d06dc5c6cd0178d7b2754248f556e9/src/worker.js#L192-L219&quot;&gt;provided with a set of information&lt;/a&gt;, such as stack size, thread ID, shared memory, etc… The same WebAssembly module as the main loop one is loaded in memory in the worker, and &lt;a href=&quot;https://github.com/emscripten-core/emscripten/blob/4bd0bc3817d06dc5c6cd0178d7b2754248f556e9/src/worker.js#L235&quot;&gt;executes the entry point&lt;/a&gt; requested for the thread.&lt;/p&gt;

&lt;p&gt;One interesting aspect of threading is that the creation of WebWorkers needs main loop to yield. This means that if the main loop does not yield control back to the environment, threads may never get the chance to start. That’s why Emscripten provides a way set of workers (none by default) to be created before executing any code.&lt;/p&gt;

&lt;p&gt;At this point, it is important to note that if the &lt;strong&gt;atomics&lt;/strong&gt; feature is not enabled in the browser (e.g. in Firefox or Safari), the emscripten built app will fail to start. This will most probably one of the reason that the &lt;a href=&quot;https://github.com/unoplatform/Uno.Wasm.Bootstrap&quot;&gt;Uno.Wasm.Bootstrap project&lt;/a&gt; will include multi-configuration generation based on browsers capabilities.&lt;/p&gt;

&lt;h2 id=&quot;threads-in-net-for-webassembly&quot;&gt;Threads in .NET for WebAssembly&lt;/h2&gt;

&lt;p&gt;.NET for WebAssembly now supports the ability to create threads, as the runtime (Mono) uses pthreads. All the existing internal .NET threading APIs have been enabled to make use of pthreads as they do for other platforms, and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Threading&lt;/code&gt; becomes available for use.&lt;/p&gt;

&lt;p&gt;With this it becomes possible to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Monitor&lt;/code&gt; (with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lock()&lt;/code&gt; statements), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AutoResetEvent&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ManualResetEvent&lt;/code&gt; and other synchronization primitives are working as intended between threads.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ThreadPool&lt;/code&gt; is also available, along with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Threading.Thread.ManagedThreadId&lt;/code&gt;, thread names and thread local storage (TLS).&lt;/p&gt;

&lt;h2 id=&quot;trying-out-webassembly-threading-with-unowasmbootstrap&quot;&gt;Trying out WebAssembly Threading with Uno.Wasm.Bootstrap&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/unoplatform/Uno.Wasm.Bootstrap&quot;&gt;Uno.Wasm.Bootstrap package&lt;/a&gt; provides the configuration to &lt;a href=&quot;https://github.com/unoplatform/Uno.Wasm.Bootstrap#threads-support&quot;&gt;enable threading&lt;/a&gt; in .NET for WebAssembly by using &lt;a href=&quot;https://www.nuget.org/packages/Uno.Wasm.Bootstrap&quot;&gt;the latest 1.1-dev package&lt;/a&gt;, and changing the active runtime mode.&lt;/p&gt;

&lt;p&gt;This can be done in the project file like this:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;MonoWasmRuntimeConfiguration&amp;gt;&lt;/span&gt;threads-release&lt;span class=&quot;nt&quot;&gt;&amp;lt;/MonoWasmRuntimeConfiguration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After that, creating a thread becomes possible (view the &lt;a href=&quot;https://github.com/jeromelaban/Wasm.Samples/tree/master/Threading/WasmThreading&quot;&gt;full project here&lt;/a&gt;):&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/jeromelaban/f4b511c85631e3a8b390409db29159a2.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Which produces the following output:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[tid:1] Startup
[tid:1] Waiting for completion source
[tid:2] Thread begin
[tid:2] Waiting for event
[tid:1] Got task result, raising event
[tid:1] Main thread exiting
[tid:2] Got event, terminating thread
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The execution is now interleaved properly, as expected when running this sample in common .NET environment.&lt;/p&gt;

&lt;p&gt;This sample is build to work with no available upfront WebWorkers, which is why the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Run&lt;/code&gt; method is invoked as Fire and Forget, so that the main loop can get the chance to start the workers.&lt;/p&gt;

&lt;p&gt;The bootstrapper configuration does not yet provide a way to change the preexisting workers, but will soon get it.&lt;/p&gt;

&lt;h2 id=&quot;threading-affinity&quot;&gt;Threading affinity&lt;/h2&gt;

&lt;p&gt;API thread affinity is a tricky subject. Most browser APIs can only be invoked from the main loop, such as DOM manipulation.&lt;/p&gt;

&lt;p&gt;Emscripten provides a &lt;a href=&quot;https://emscripten.org/docs/porting/pthreads.html#proxying&quot;&gt;feature called “Proxying”&lt;/a&gt; which detects APIs need to be invoked on the main loop. The user code is then rewriten to create a blocking call in the worker until the method execution finishes on the other thread. This execution is done through WebWorkers message passing, but this is not something that we’ll be able to use in .NET, as IL does not use the proper APIs to executed proxied code.&lt;/p&gt;

&lt;p&gt;Along with those limitations are the inability for the main loop to be blocked. Emscripten provides a way to &lt;a href=&quot;https://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread&quot;&gt;seemingly block the main&lt;/a&gt; thread through spinlocks, though that’s generally not a good idea for the end user perceived performance.&lt;/p&gt;

&lt;h2 id=&quot;coming-next&quot;&gt;Coming next…&lt;/h2&gt;

&lt;p&gt;I’ll continue the story on how enable threading in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoreDispatcher.RunAsync()&lt;/code&gt; in the Uno Platform.&lt;/p&gt;</content><author><name>Jerome</name></author><category term="Archive" /><category term=".NET" /><category term="Threading" /><category term="WebAssembly" /><summary type="html">Threading, in general operating systems sense, is not something that the web has been able to use until very recently. The addition of Threads support in WebAssembly, and the activation of the threading support in Chrome opens up a whole new world of possibilities, including the use of Reactive Extensions (Rx.NET) or the Task Parallel Library (TPL). Let’s dive in, with some sample code.</summary></entry><entry><title type="html">Roslyn Source Generation Reborn, the replace keyword and INotifyPropertyChanged</title><link href="https://jaylee.org/archive/2019/12/08/roslyn-sourcegeneration-reborn-replace-inotifypropertychanged.html" rel="alternate" type="text/html" title="Roslyn Source Generation Reborn, the replace keyword and INotifyPropertyChanged" /><published>2019-12-08T05:00:00+00:00</published><updated>2019-12-08T05:00:00+00:00</updated><id>https://jaylee.org/archive/2019/12/08/roslyn-sourcegeneration-reborn-replace-inotifypropertychanged</id><content type="html" xml:base="https://jaylee.org/archive/2019/12/08/roslyn-sourcegeneration-reborn-replace-inotifypropertychanged.html">&lt;p&gt;A very long time ago, during the C# 6.0 time frame, a Source Generation proposal was added to the list of possible features, it was abandoned, but in a recent PR, the Roslyn team &lt;a href=&quot;https://github.com/dotnet/roslyn/pull/40162&quot;&gt;is taking a look again&lt;/a&gt; at the feature proposal, as there are lots of generation happen around Microsoft that could benefit from an integrated story.&lt;/p&gt;

&lt;!-- more --&gt;
&lt;h2 id=&quot;the-original-feature-of-c-60&quot;&gt;The original feature of C# 6.0&lt;/h2&gt;
&lt;p&gt;One of its goals were to tackle the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INotifyPropertyChanged&lt;/code&gt; (INPC) problem, where having to manually raise the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PropertyChanged&lt;/code&gt; event was a very repetitive task. That feature could have enabled very interesting scenarios such as the inclusion of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;replace&lt;/code&gt; keyword. It could allow for a source generator to replace the content of a method (a property setter for instance), with another method, while allowing it to call back the original method through an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;original&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;The objectives were probably a bit too broad at the time. The implications with the build pipeline as a whole, and particularly with the IDE were a bit too large to chew. I &lt;a href=&quot;https://jaylee.org/archive/2019/01/06/improving-out-of-process-csharp-source-generation-performance.html&quot;&gt;discussed that a little bit&lt;/a&gt; in article I wrote a few months ago.&lt;/p&gt;

&lt;p&gt;At time though, I though it would still be interesting to write a source generator that would have less ambitious goals, but still would allow for source generation in a build pipeline, even if it would not be tightly integrated in Roslyn. That’s how the Uno.SourceGeneration project was born.&lt;/p&gt;

&lt;p&gt;It’s still going strong as it is used throughout Uno, to solve a large variety of problems.&lt;/p&gt;

&lt;h2 id=&quot;source-generation-reborn&quot;&gt;Source Generation reborn&lt;/h2&gt;

&lt;p&gt;In most recent use cases at Microsoft, the use of T4 templates seems to be the choice, and it has its set of issues such as build performance, the inability to work on partially valid or complete source trees, the inability to use information from the syntactic model or the duplication of the semantic model work.&lt;/p&gt;

&lt;p&gt;The team is looking at a smaller set of features, removing the ability to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;replace&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;original&lt;/code&gt;, but provide an end to end experience that includes the IDE, something that the &lt;a href=&quot;https://github.com/unoplatform/Uno.SourceGeneration&quot;&gt;Uno.SourceGeneration framework&lt;/a&gt; is not able to support completely.&lt;/p&gt;

&lt;p&gt;This would solve one of the most glaring issue of source generation in Visual Studio, where arbitrary modified files (e.g. non XAML files) can’t re-rerun the generation without an explicit build, and where intellisense caching is getting in the way of using generated file symbols.&lt;/p&gt;

&lt;h2 id=&quot;the-inotifypropertychanged-case&quot;&gt;The INotifyPropertyChanged case&lt;/h2&gt;

&lt;p&gt;As &lt;a href=&quot;https://github.com/dotnet/roslyn/pull/40162#issuecomment-562971937&quot;&gt;Robin Sue mentions&lt;/a&gt;, the often requested scenario for generation is &lt;em&gt;INPC&lt;/em&gt;, for which tagging a property automatically raising the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PropertyChanged&lt;/code&gt; event, will not be addressed by the newly proposed version of the feature.&lt;/p&gt;

&lt;p&gt;There’s still a way around this, albeit a bit more verbose or at first counter intuitive. Generating source in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;replace&lt;/code&gt;-less model requires to make use of partial classes and methods, and more generally delegate the creation of significant language items to the source generator.&lt;/p&gt;

&lt;p&gt;For the case of INPC, it is possible to write a class this way:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;partial&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyClass&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GeneratedProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_myProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;partial&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnMyPropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;previousValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;OnMyPropertyChanged(&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;previousValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice here that the property is not visible at all, and it will be assumed that the generator will recognize the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GeneratedPropertyAttribute&lt;/code&gt; and do the rest of the work for the author of the class.&lt;/p&gt;

&lt;p&gt;The generator could then produce something like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;partial&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyClass&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;INotifyPropertyChanged&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyProperty&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_myProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;previous&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_myProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;_myProperty&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;PropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Invoke&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;PropertyChangedEventArgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)));&lt;/span&gt;
      &lt;span class=&quot;nf&quot;&gt;OnMyPropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;previous&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;partial&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnMyPropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;previousValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The complete property body is then generated with the appropriate boiler plate. It can also include a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OnMyPropertyChanged&lt;/code&gt; method that can optionally be implemented as needed in the main class to react to the property changes. Same could also be done for the getter, if there’s work to be done in that context.&lt;/p&gt;

&lt;p&gt;In the end, users of the class won’t notice that the properties were generated.&lt;/p&gt;

&lt;p&gt;This approach is not without drawbacks, though. For instance, documentation is not generated here, and the generator may need to forward the documentation of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_myProperty&lt;/code&gt; field over to the generated property. The same applies to the attributes that may be needed on that property; it’s not possible to apply an attribute on a property defined in another partial type declaration.&lt;/p&gt;

&lt;h2 id=&quot;implementing-the-field-backed-inpc-generator&quot;&gt;Implementing the field backed INPC generator&lt;/h2&gt;

&lt;p&gt;Let’s try creating this generator using the Uno.SourceGeneration package. Its API is very similar to the current Roslyn proposal (aside from the optional msbuild ties). It could be easily ported over to a future roslyn-based implementation of the generators if it does not change too much.&lt;/p&gt;

&lt;p&gt;First, we can assume that there will be an available property named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INPC.GeneratedPropertyAttribute&lt;/code&gt;, which allows us to find its symbol:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;INPCGenerator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SourceGenerator&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SourceGeneratorContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Search for the GeneratedPropertyAttribute symbol&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_generatedPropertyAttributeSymbol&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Compilation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetTypeByMetadataName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;INPC.GeneratedPropertyAttribute&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will ease our ability to find fields in types that are tagged with this attribute.&lt;/p&gt;

&lt;p&gt;Now let’s find those tagged fields:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Search in all types defined in the current compilation (but not in the dependents)&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; 
    &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typeSymbol&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Compilation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SourceModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GlobalNamespace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetNamespaceTypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typeSymbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetFields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Find the attribute on the field&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;info&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FindAttributeFlattened&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_generatedPropertyAttributeSymbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;info&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Group properties by type&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;typeSymbol&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;into&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will create a grouped &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IEnumerable&lt;/code&gt;, for which the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Key&lt;/code&gt; is the owner of the marked fields, and the group items are the fields symbols.&lt;/p&gt;

&lt;p&gt;Then we can generate the class and the properties plumbing:&lt;/p&gt;
&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IndentedStringBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AppendLineInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;using System;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AppendLineInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;using System.ComponentModel;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BlockInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;namespace &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ContainingNamespace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Add the INotifyPropertyChanged interface to the existing type&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BlockInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;partial class &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; : INotifyPropertyChanged&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// Implement the event itself&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AppendLineInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;public event PropertyChangedEventHandler PropertyChanged;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fieldInfo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Uppercase name for camel case&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;propertyName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fieldInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;TrimStart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;'_'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;propertyName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToUpperInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Substring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Create the property body&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BlockInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;public &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fieldInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AppendLineInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;get =&amp;gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fieldInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

          &lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;BlockInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;set&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AppendLineInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;var previous = &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fieldInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AppendLineInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fieldInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; = value;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AppendLineInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;$&quot;PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;)));&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AppendLineInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;On&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Changed(previous, value);&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AppendLineInvariant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;$&quot;partial void On&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Changed(&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fieldInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; previous, &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fieldInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; value);&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sanitizedName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToDisplayString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddCompilationUnit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sanitizedName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And it’s done! It’s a big string generator that most probably produces valid C#, depending on the efficiency of the type names sanitization (to remove non-valid characters).&lt;/p&gt;

&lt;p&gt;This generator makes use of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Uno.Roslyn&lt;/code&gt; package, which provides a set of helpers to browser the types and their members more easily, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetNamespaceTypes()&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FindAttributeFlattened()&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetFields()&lt;/code&gt;. It also provides the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IndentedStringBuilder&lt;/code&gt; class, which allows for a nicely formatted generated files (because developers always want to read generated code 😊).&lt;/p&gt;

&lt;p&gt;Finally, here’s how to create a class that uses it :&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;INPC&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;GeneratedPropertyAttribute&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Attribute&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;partial&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyClass&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GeneratedProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_stringProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GeneratedProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_intProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;partial&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnIntPropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;previous&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;OnIntPropertyChanged(&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;previous&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;partial&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnStringPropertyChanged&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;previous&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
        &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;OnIntPropertyChanged(&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;previous&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And how to use it:&lt;/p&gt;
&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MyClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IntProperty&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringProperty&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;My 42&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Output:&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// OnIntPropertyChanged(0,42)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// OnIntPropertyChanged(,My 42)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;

&lt;p&gt;This generator does not handle all possible cases for properties generation, such as nested types or fancy identifier names. That leaves lots to experiment with if you choose source generation to enable this scenario for your project.&lt;/p&gt;

&lt;p&gt;You can find a &lt;a href=&quot;https://github.com/jeromelaban/inpc.generator&quot;&gt;sample solution for this generator on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That’s it for now! Until next time, happy source-gen’ing!&lt;/p&gt;</content><author><name>Jerome</name></author><category term="Archive" /><category term=".NET" /><category term="C#" /><category term="Source Generation" /><summary type="html">A very long time ago, during the C# 6.0 time frame, a Source Generation proposal was added to the list of possible features, it was abandoned, but in a recent PR, the Roslyn team is taking a look again at the feature proposal, as there are lots of generation happen around Microsoft that could benefit from an integrated story.</summary></entry><entry><title type="html">MVP 2020-2021</title><link href="https://jaylee.org/archive/2019/12/01/mvp-2020-2021.html" rel="alternate" type="text/html" title="MVP 2020-2021" /><published>2019-12-01T05:00:00+00:00</published><updated>2019-12-01T05:00:00+00:00</updated><id>https://jaylee.org/archive/2019/12/01/mvp-2020-2021</id><content type="html" xml:base="https://jaylee.org/archive/2019/12/01/mvp-2020-2021.html">&lt;p&gt;What a year!&lt;/p&gt;

&lt;p&gt;I’ve been doing full Open Source work for the past year and a half, giving talks about .NET, Xamarin, Mono and WebAssembly, contributing to open source projects, and Microsoft noticed!&lt;/p&gt;

&lt;p&gt;I’ve been awarded &lt;a href=&quot;https://mvp.microsoft.com/&quot;&gt;MVP&lt;/a&gt; by Microsoft for 2020-2021 for the Developer Technologies, 8 years after being a “Visual C#” MVP from 2009 to 2011.&lt;/p&gt;

&lt;p&gt;I’d like to personally thank the amazing MVPs that supported me through this process, &lt;a href=&quot;https://twitter.com/archiecoder&quot;&gt;Sébastien Lachance&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/GraniteStHacker&quot;&gt;Jim Wilcox&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/GeoffreyHuntley&quot;&gt;Geoffrey Huntley&lt;/a&gt;, as well as Microsoft employees (Thanks Clint, Karel, Rochelle, Jesus, Ryan, Betsy).&lt;/p&gt;

&lt;p&gt;I’m glad to be back as an MVP, and off to a new year with this great community!&lt;/p&gt;</content><author><name>Jerome</name></author><category term="Archive" /><category term="MVP" /><category term=".NET" /><summary type="html">What a year! I’ve been doing full Open Source work for the past year and a half, giving talks about .NET, Xamarin, Mono and WebAssembly, contributing to open source projects, and Microsoft noticed! I’ve been awarded MVP by Microsoft for 2020-2021 for the Developer Technologies, 8 years after being a “Visual C#” MVP from 2009 to 2011. I’d like to personally thank the amazing MVPs that supported me through this process, Sébastien Lachance, Jim Wilcox, Geoffrey Huntley, as well as Microsoft employees (Thanks Clint, Karel, Rochelle, Jesus, Ryan, Betsy). I’m glad to be back as an MVP, and off to a new year with this great community!</summary></entry><entry><title type="html">NuGet, Visual Studio 2019 Solution Filters and Large Cross-targeted Solutions</title><link href="https://jaylee.org/archive/2019/06/29/nuget-visualstudio-and-large-cross-targeted-solutions.html" rel="alternate" type="text/html" title="NuGet, Visual Studio 2019 Solution Filters and Large Cross-targeted Solutions" /><published>2019-06-29T05:00:00+00:00</published><updated>2019-06-29T05:00:00+00:00</updated><id>https://jaylee.org/archive/2019/06/29/nuget-visualstudio-and-large-cross-targeted-solutions</id><content type="html" xml:base="https://jaylee.org/archive/2019/06/29/nuget-visualstudio-and-large-cross-targeted-solutions.html">&lt;p&gt;The combination of the &lt;a href=&quot;https://docs.microsoft.com/en-us/visualstudio/ide/filtered-solutions?view=vs-2019&quot;&gt;Visual Studio solution filtering&lt;/a&gt; and &lt;a href=&quot;https://github.com/NuGet/Home/issues/5820&quot;&gt;NuGet support for it&lt;/a&gt; allows for faster trimmed-down solution loading. This enables developers of large cross-targeted solutions to have a viable environment by temporarily focusing on a single target framework, and still have Visual Studio cooperate.&lt;/p&gt;

&lt;!-- more --&gt;
&lt;h2 id=&quot;cross-targeted-projects-support-in-visual-studio&quot;&gt;Cross-targeted projects support in Visual Studio&lt;/h2&gt;

&lt;p&gt;Since the introduction of the new msbuild project file structure (also known as &lt;a href=&quot;https://github.com/dotnet/project-system&quot;&gt;Common Project System or CPS&lt;/a&gt;), it’s been increasingly easy to create libraries that target multiple platforms at once. &lt;a href=&quot;https://github.com/onovotny/MSBuildSdkExtras&quot;&gt;Oren’s msbuild.sdk.extras&lt;/a&gt; definitely helped a lot to make this seamless.&lt;/p&gt;

&lt;p&gt;It’s been a delight to use at first, as it replaces linked files and a myriad of framework specific projects, makes the creation of &lt;a href=&quot;https://docs.microsoft.com/en-us/nuget/reference/msbuild-targets&quot;&gt;multi-targeted NuGet packages&lt;/a&gt;, supports &lt;a href=&quot;https://docs.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#adding-a-packagereference-condition&quot;&gt;conditional project and package references&lt;/a&gt;, and many other features.&lt;/p&gt;

&lt;p&gt;But not all is rosy. The impact of this new project format on Visual Studio, and on NuGet is very significant. Each new target framework specified in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;TargetFrameworks&amp;gt;&lt;/code&gt; property is actually creating a new independent project in memory, even if large parts of the project definition are the same. For instance, using &lt;a href=&quot;https://github.com/unoplatform/uno/blob/master/src/PlatformItemGroups.props#L52-L56&quot;&gt;conditional globbing to include files per target framework&lt;/a&gt; can give a hard time to Visual Studio.&lt;/p&gt;

&lt;p&gt;The CPU goes up significantly, memory as well (along with longer GC pauses), where it’s very easy to reach the 32 bits process memory limit (and the &lt;a href=&quot;https://blogs.msdn.microsoft.com/ricom/2009/06/10/visual-studio-why-is-there-no-64-bit-version-yet/&quot;&gt;old 64 bits debate&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Intellisense is also impacted, as for each file present in a target framework, each popup showing types information has to iterate through all of them. NuGet is impacted in the same way.&lt;/p&gt;

&lt;h2 id=&quot;how-did-we-get-here-&quot;&gt;How did we get here ?&lt;/h2&gt;

&lt;p&gt;Through quite a natural flow. Xamarin.iOS, Xamarin.Android (per SDK version), Xamarin.Mac, UWP, .NET Core, WebAssembly, .NET Standard, etc… are valid targets for many libraries that provide abstractions over platforms. &lt;a href=&quot;https://github.com/unoplatform/uno&quot;&gt;The Uno Platform&lt;/a&gt; is a prime target for that, as each platform gets its own implementation of the UWP API.&lt;/p&gt;

&lt;p&gt;This means that to get a valid solution, validate builds for all targets, and provided in-solution sample applications to get a proper debugging experience, it’s required to include all those target frameworks. And there can be many of those, as many upcoming (.NET Standard 2.0, netcoreapp 3.0, uap versions, etc…)&lt;/p&gt;

&lt;h2 id=&quot;temporarily-reducing-the-target-framework-count&quot;&gt;Temporarily reducing the target framework count&lt;/h2&gt;

&lt;p&gt;In general, when developing a cross-targeted library, it’s very rare to work on multiple targets at once. This means that reducing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TargetFrameworks&lt;/code&gt; count during a development session can make sense.&lt;/p&gt;

&lt;p&gt;Problem is that when reducing the number of target frameworks from many to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xamarinios10&lt;/code&gt;, for instance, will make NuGet fail to restore the solution. This happens because some projects (sample apps generally) won’t be able to find valid target frameworks from their dependencies, as they’ve been removed (e.g. an android app references a library that should support &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;monoandroid90&lt;/code&gt;, but only supports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xamarinios10&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;A temporary solution is to make multiple solutions, but this gets out of hands very quickly when new projects get added to the main solution, and trimmed-down solutions don’t.&lt;/p&gt;

&lt;h2 id=&quot;combining-solution-filtering-and-single-target-frameworks&quot;&gt;Combining solution filtering and single target frameworks&lt;/h2&gt;

&lt;p&gt;Visual Studio added the &lt;a href=&quot;https://docs.microsoft.com/en-us/visualstudio/ide/filtered-solutions?view=vs-2019&quot;&gt;Solution Filtering feature&lt;/a&gt; recently, which gives the ability to create a partially loaded solution for an improved IDE experience. There are two nice touches for this feature, with unloaded projects being hidden by default when a solution is opened from an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.slnf&lt;/code&gt; file, and also the file format being json, not the exotic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.sln&lt;/code&gt; format.&lt;/p&gt;

&lt;p&gt;From the outside, this seems like &lt;em&gt;just&lt;/em&gt; a nice solution to load less projects. It does not allow to reduce the number of loaded target frameworks &lt;strong&gt;per project&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But, hidden there, in the &lt;a href=&quot;https://github.com/NuGet/Home/issues/5820&quot;&gt;NuGet changelog&lt;/a&gt;, is the the fact that the NuGet restore operation is now able to take the solution filtering into account, and &lt;strong&gt;ignore&lt;/strong&gt; unloaded projects!&lt;/p&gt;

&lt;p&gt;This means that it’s now possible to create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Directory.Build.Props&lt;/code&gt; file with this content:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ToolsVersion=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;15.0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!--&amp;lt;TargetFrameworkOverride&amp;gt;netstandard2.0&amp;lt;/TargetFrameworkOverride&amp;gt;--&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And for each project that can be adjusted, the following:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Sdk=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MSBuild.Sdk.Extras&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ToolsVersion=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;15.0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;TargetFrameworks&amp;gt;&lt;/span&gt;xamarinmac20;xamarinios10;MonoAndroid90;net461;netstandard2.0&lt;span class=&quot;nt&quot;&gt;&amp;lt;/TargetFrameworks&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;PropertyGroup&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Condition=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;'$(TargetFrameworkOverride)'!=''&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;TargetFrameworks&amp;gt;&lt;/span&gt;$(TargetFrameworkOverride)&lt;span class=&quot;nt&quot;&gt;&amp;lt;/TargetFrameworks&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When debugging or developing for a specific target framework, un-commenting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TargetFrameworkOverride&lt;/code&gt; will essentially change the active target framework, and have Visual Studio only consider that one.&lt;/p&gt;

&lt;p&gt;After that, to avoid having NuGet fail for projects that are not valid, &lt;a href=&quot;https://docs.microsoft.com/en-us/visualstudio/ide/filtered-solutions?view=vs-2019#create-a-solution-filter-file&quot;&gt;create a solution filter file&lt;/a&gt;, and make sure to use it when appropriate.&lt;/p&gt;

&lt;p&gt;A few things to note:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Changing that property must not be done when the solution is loaded, otherwise project and NuGet caching issues may arise, exposing instabilities in Visual Studio’s project system.&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.slnf&lt;/code&gt; format is &lt;a href=&quot;https://github.com/microsoft/msbuild/issues/4097&quot;&gt;not supported by CLI msbuild&lt;/a&gt;, which makes the use of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TargetFrameworkOverride&lt;/code&gt; fail the build, as all the projects of the solution will be tentatively restored, incorrectly.&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TargetFrameworkOverride&lt;/code&gt; property should be &lt;a href=&quot;https://github.com/unoplatform/uno/blob/9a70fb6df74cf64c40d22c4033d3d111c13dd1fb/src/Directory.Build.props#L3&quot;&gt;declared in a file that is excluded from source control&lt;/a&gt;, so that it does not unwillingly break a build.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h2&gt;

&lt;p&gt;It still feels like a hack, because cross-targeting is not yet a first class citizen in Visual Studio.&lt;/p&gt;

&lt;p&gt;Yet, it definitely does work properly and gives a &lt;strong&gt;lot&lt;/strong&gt; of processing power and time back to the developer, even it is at the expense of being able to view all target frameworks at once.&lt;/p&gt;</content><author><name>Jerome</name></author><category term="Archive" /><category term=".NET" /><category term="xamarin" /><category term="msbuild" /><summary type="html">The combination of the Visual Studio solution filtering and NuGet support for it allows for faster trimmed-down solution loading. This enables developers of large cross-targeted solutions to have a viable environment by temporarily focusing on a single target framework, and still have Visual Studio cooperate.</summary></entry><entry><title type="html">Using the Span in Xamarin Cross-Targeted projects</title><link href="https://jaylee.org/archive/2019/03/31/using-span-of-t-in-xamarin-cross-targeted-projects.html" rel="alternate" type="text/html" title="Using the Span in Xamarin Cross-Targeted projects" /><published>2019-03-31T05:00:00+00:00</published><updated>2019-03-31T05:00:00+00:00</updated><id>https://jaylee.org/archive/2019/03/31/using-span-of-t-in-xamarin-cross-targeted-projects</id><content type="html" xml:base="https://jaylee.org/archive/2019/03/31/using-span-of-t-in-xamarin-cross-targeted-projects.html">&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Memory&lt;/code&gt; exists to provide the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Span&amp;lt;T&amp;gt;&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Memory&amp;lt;T&amp;gt;&lt;/code&gt; and similar types, for which &lt;a href=&quot;https://msdn.microsoft.com/en-us/magazine/mt814808.aspx&quot;&gt;C# 7.x provided support&lt;/a&gt;, and it can enable significant performance improvements where appropriate. While .NET Standard 2.0 does not have support for it in its available API surface, there the &lt;a href=&quot;https://www.nuget.org/packages/System.Memory&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Memory&lt;/code&gt;&lt;/a&gt; NuGet package that can be added to enable it.&lt;/p&gt;

&lt;p&gt;As part of the code sharing effort, Mono and Xamarin added support for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Memory&lt;/code&gt; in the BCL as part of the releases bundled with VS 2019.&lt;/p&gt;

&lt;p&gt;While this is a very important step to make Mono and .NET Core very similar in behavior, this brings issues because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Xamarin.iOS&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Xamarin.Mac&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MonoAndroid&lt;/code&gt; target frameworks are not versioned like .NET Core or .NET Standard. The Visual Studio version used to build a project has an impact on the code’s behavior or compatibility that cannot be adjusted as easily as changing a Target Framework version.&lt;/p&gt;

&lt;!-- more --&gt;
&lt;h2 id=&quot;vs2019-issues&quot;&gt;VS2019 issues&lt;/h2&gt;
&lt;p&gt;In VS2019, the following code :&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Span&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;with a project file like this:&lt;/p&gt;
&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Sdk=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MSBuild.Sdk.Extras/1.6.46&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;TargetFrameworks&amp;gt;&lt;/span&gt;xamarinios10;monoandroid90&lt;span class=&quot;nt&quot;&gt;&amp;lt;/TargetFrameworks&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;System.Memory&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;4.5.2&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;does not build in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Xamarin.iOS10&lt;/code&gt;, giving this error:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;
error CS0433: The type 'Span&amp;lt;T&amp;gt;' exists in both 
'System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' and 
'mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e'
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;One easy fix would be to remove the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Memory&lt;/code&gt; package because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mscorlib&lt;/code&gt; already provides it, but it would prevent this library from building with VS15.9 and below.&lt;/p&gt;

&lt;p&gt;We could also only add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Memory&lt;/code&gt; as a normal assembly reference, which would work on both VS versions, but it would break the NuGet package creation and make the consumption of the project’s resulting NuGet package difficult.&lt;/p&gt;

&lt;h2 id=&quot;adjusting-references-during-the-build&quot;&gt;Adjusting references during the build&lt;/h2&gt;

&lt;p&gt;In recent MSBuild, there is a new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MSBuildVersion&lt;/code&gt; property which tells the currently running version. While this is far from perfect, we can assume that when a given MSBuild version is installed at the same time as Xamarin for an installation of Visual Studio, the MSBuild version is implicitly tied to the installed Xamarin version.&lt;/p&gt;

&lt;p&gt;To keep the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PackageReference&lt;/code&gt; visible for the NuGet packing, but remove the assembly reference added by the package, only in VS16.x, we can inject an MSBuild target:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;Project&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Sdk=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;MSBuild.Sdk.Extras/1.6.46&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;TargetFrameworks&amp;gt;&lt;/span&gt;xamarinios10&lt;span class=&quot;nt&quot;&gt;&amp;lt;/TargetFrameworks&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;System.Memory&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Version=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;4.5.2&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
  
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;Target&lt;/span&gt; 
    &lt;span class=&quot;na&quot;&gt;Name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;VS16_RemoveSystemMemory&quot;&lt;/span&gt; 
    &lt;span class=&quot;na&quot;&gt;BeforeTargets=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;FindReferenceAssembliesForReferences&quot;&lt;/span&gt; 
    &lt;span class=&quot;na&quot;&gt;Condition=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;'$(MSBuildVersion)' &amp;amp;gt;= '16.0'&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;_ReferencePathToRemove&lt;/span&gt; 
        &lt;span class=&quot;na&quot;&gt;Include=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;@(ReferencePath)&quot;&lt;/span&gt; 
        &lt;span class=&quot;na&quot;&gt;Condition=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;'%(ReferencePath.NuGetPackageId)'=='System.Memory'&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;ReferencePath&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Remove=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;@(_ReferencePathToRemove)&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;Message&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Text=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Removing System.Memory for VS 2019 compatibility&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Importance=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;high&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Target&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;'$(MSBuildVersion)' &amp;amp;gt;= '16.0'&lt;/code&gt; condition ensure that the target only runs when VS 16.0 is used to build the project. Then we remove the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReferencePath&lt;/code&gt; item that is generated by the loading of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;PackageReference Include=&quot;System.Memory&quot; /&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The target is injected automatically before the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FindReferenceAssembliesForReferences&lt;/code&gt; that can be found by looking at the generated binary log, and searching where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReferencePath&lt;/code&gt; values are manipulated to be provided to the CSC task.&lt;/p&gt;

&lt;p&gt;Interestingly enough, this manipulation does not need to be made in Xamarin.iOS head projects, where the reference seems to be automatically adjusted to be removed by the existing targets.&lt;/p&gt;</content><author><name>Jerome</name></author><category term="Archive" /><category term=".NET" /><category term="xamarin" /><summary type="html">System.Memory exists to provide the Span&amp;lt;T&amp;gt;, Memory&amp;lt;T&amp;gt; and similar types, for which C# 7.x provided support, and it can enable significant performance improvements where appropriate. While .NET Standard 2.0 does not have support for it in its available API surface, there the System.Memory NuGet package that can be added to enable it. As part of the code sharing effort, Mono and Xamarin added support for System.Memory in the BCL as part of the releases bundled with VS 2019. While this is a very important step to make Mono and .NET Core very similar in behavior, this brings issues because the Xamarin.iOS, Xamarin.Mac and MonoAndroid target frameworks are not versioned like .NET Core or .NET Standard. The Visual Studio version used to build a project has an impact on the code’s behavior or compatibility that cannot be adjusted as easily as changing a Target Framework version.</summary></entry></feed>