{"id":89800,"date":"2023-08-03T07:44:31","date_gmt":"2023-08-03T05:44:31","guid":{"rendered":"https:\/\/drafts.code-maze.com\/?p=89800"},"modified":"2023-08-16T09:15:52","modified_gmt":"2023-08-16T07:15:52","slug":"csharp-source-generators","status":"publish","type":"post","link":"https:\/\/code-maze.com\/csharp-source-generators\/","title":{"rendered":"Source Generators in C#"},"content":{"rendered":"<p>Traditionally, code generation in C# involved using external tools or templates to generate code before the compilation process, like the T4 template. However, with source generators, code generation becomes an integral part of the compilation itself.<\/p>\n<p>In this article, we&#8217;ll explore the basics of C# source generators and how to use this powerful feature to enable dynamic code generation during compilation, automating repetitive tasks, and improving developer productivity.<\/p>\n<div style=\"padding: 20px; border-left: 5px #dc2323 solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\">To download the source code for this article, you can visit our <a href=\"https:\/\/github.com\/CodeMazeBlog\/CodeMazeGuides\/tree\/main\/csharp-advanced-topics\/SourceGeneratorInCSharp\" target=\"_blank\" rel=\"nofollow noopener\">GitHub repository<\/a>.<\/div>\n<p>Let&#8217;s start.<\/p>\n<h2>Background<\/h2>\n<p>Source generators are a feature introduced in C# 9 that allows dynamic code generation during the compilation process. They integrate directly with the C# compiler <code>(Roslyn)<\/code> and operate at compile time, analyzing source code and generating additional code based on analysis results.<\/p>\n<p>Source generators provide a streamlined, automated approach to code generation, eliminating the need for external tools or separate pre-compilation steps.<\/p>\n<p>By seamlessly integrating into the compilation process, source generators enhance productivity, reduce errors, and allow for more efficient development workflows.<\/p>\n<h2>How to Use It<\/h2>\n<p>First, we should create a C# project that targets <code>netstandard2.0<\/code> and add some standard packages to get access to the source generator types.<\/p>\n<p>We can start by creating a class library. Then, through the SDK, we can create a solution and a project in the current folder:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\">dotnet new sln -n SourceGeneratorInCSharp\r\ndotnet new classlib --framework \"netstandard2.0\" -o .\/Generator\r\ndotnet sln add .\/Generator<\/pre>\n<p>Afterward, we need to replace the content of <code>Generator.csproj<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;Project Sdk=\"Microsoft.NET.Sdk\"&gt;\r\n    &lt;PropertyGroup&gt;\r\n        &lt;TargetFramework&gt;netstandard2.0&lt;\/TargetFramework&gt;\r\n        &lt;IncludeBuildOutput&gt;false&lt;\/IncludeBuildOutput&gt;\r\n        &lt;LangVersion&gt;latest&lt;\/LangVersion&gt;\r\n    &lt;\/PropertyGroup&gt;\r\n\r\n    &lt;ItemGroup&gt;\r\n        &lt;PackageReference Include=\"Microsoft.CodeAnalysis.CSharp.Workspaces\" \r\n            Version=\"4.4.0\" \r\n            PrivateAssets=\"all\" \/&gt;\r\n    &lt;\/ItemGroup&gt;\r\n&lt;\/Project&gt;<\/pre>\n<p>As we know, source code generators work like an analyzer and provide an option to generate source code at development time even if the code cannot be compiled. For this, we need a separate project to reference our generator.<\/p>\n<p>Let&#8217;s create a console application for this:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\">dotnet new console --framework \"net7.0\" -o SourceGeneratorInCSharp\r\ndotnet sln add SourceGeneratorInCSharp<\/pre>\n<p>In the <code>SourceGeneratorInCSharp.csproj<\/code> we need to change the content:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;Project Sdk=\"Microsoft.NET.Sdk\"&gt;\r\n    &lt;PropertyGroup&gt;\r\n        &lt;OutputType&gt;Exe&lt;\/OutputType&gt;\r\n        &lt;TargetFramework&gt;net7.0&lt;\/TargetFramework&gt;\r\n        &lt;LangVersion&gt;latest&lt;\/LangVersion&gt;\r\n        &lt;ImplicitUsings&gt;enable&lt;\/ImplicitUsings&gt;\r\n        &lt;Nullable&gt;enable&lt;\/Nullable&gt;\r\n    &lt;\/PropertyGroup&gt;\r\n\r\n    &lt;ItemGroup&gt;\r\n        &lt;ProjectReference Include=\"..\\Generator\\Generator.csproj\" \r\n            OutputItemType=\"Analyzer\" \r\n            ReferenceOutputAssembly=\"false\"\/&gt;\r\n    &lt;\/ItemGroup&gt;\r\n&lt;\/Project&gt;\r\n<\/pre>\n<p>So far, everything we&#8217;ve done has been pretty much standard stuff, so let&#8217;s get into the code.<\/p>\n<h2>Implementing a Simple Generator<\/h2>\n<p>A source generator has two defining characteristics, implementing the <code>IIncrementalGenerator\u00a0<\/code>interface and decorating with the <code>[Generator]<\/code> attribute, which makes a project consider a class as a source generator:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[Generator]\r\npublic sealed class ExampleGenerator : IIncrementalGenerator\r\n{\r\n    public void Initialize(IncrementalGeneratorInitializationContext context)\r\n    {\r\n    }\r\n}\r\n<\/pre>\n<p>The generator only requires the implementation of a single method, <code>Initialize<\/code>. In this method, we can register our static source code as well as create a pipeline to identify the syntax of interest and transform this syntax into source code.<\/p>\n<p><strong>Also, we are using the IIncrementalGenerator interface instead of ISourceGenerator because it is way more performant, and with the ISourceGenerator interface, a new ISyntaxReceiver is created for every generation, which creates a lot of generation phases. With bigger projects, this can quickly lead to performance issues. The IIncrementalGenerator was optimized to provide better performance for our applications.<\/strong><\/p>\n<p>Now, let&#8217;s implement a generator that will output a simple source code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[Generator]\r\npublic sealed class ExampleGenerator : IIncrementalGenerator\r\n{\r\n    public void Initialize(IncrementalGeneratorInitializationContext context)\r\n    {\r\n        context.RegisterPostInitializationOutput(ctx =&gt;\r\n        {\r\n            var sourceText = $$\"\"\"\r\n                namespace SourceGeneratorInCSharp\r\n                {\r\n                    public static class HelloWorld\r\n                    {\r\n                        public static void SayHello()\r\n                        {\r\n                            Console.WriteLine(\"Hello From Generator\");\r\n                        }\r\n                    }\r\n                }\r\n                \"\"\";\r\n\r\n            ctx.AddSource(\"ExampleGenerator.g\", SourceText.From(sourceText, Encoding.UTF8));\r\n        });\r\n    }\r\n}<\/pre>\n<p>In the example, we use a string literal to represent the code we want to emit.<\/p>\n<p>The <code>RegisterPostInitializationOutput<\/code> only allows us to add fixed source code, as we don&#8217;t have any access to the user code at this point.<\/p>\n<p>To emit the files, we utilize the <code>AddSource()<\/code> method, which requires two parameters. The first parameter serves as a distinct identifier for the emitted source, while the second parameter represents the actual source text. This text is obtained from our hard-coded string and includes the corresponding encoding information.<\/p>\n<p>After we build, if everything is set up properly, we can see the generated code file under the analyzer in the <code>Console<\/code> project solution explorer:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExample.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-94697 size-full\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExample.png\" alt=\"Generated file from SourceGenerators in C#\" width=\"438\" height=\"218\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExample.png 438w, https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExample-300x149.png 300w\" sizes=\"auto, (max-width: 438px) 100vw, 438px\" \/><\/a><\/p>\n<p>If we double-click the <code class=\"language-plaintext highlighter-rouge\">ExampleGenerator.g.cs<\/code> we can see the output code, including warnings from Visual Studio that this file isn\u2019t editable:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExampleDetail-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-94698\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExampleDetail-1.png\" alt=\"Code generated from Source Generators in C#\" width=\"790\" height=\"297\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExampleDetail-1.png 790w, https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExampleDetail-1-300x113.png 300w, https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExampleDetail-1-768x289.png 768w\" sizes=\"auto, (max-width: 790px) 100vw, 790px\" \/><\/a><\/p>\n<h2>Implementing a More Complex Generator<\/h2>\n<p>Now that we&#8217;ve seen how a generator works through a simple example, let&#8217;s tackle something different. Before we build a more complex generator, let&#8217;s consider a scenario for our practice.<\/p>\n<p>For many corporate applications, we have a series of architectural patterns that are followed, such as the use of entities, repositories, services, and controllers, most of which have the same implementation. This tends to be a very manual and time-consuming task. The code we need to write to create the entire structure tends to be repetitive and error-prone.<\/p>\n<p>Using C# source code generators to generate some of these parts can save us a lot of time. So let&#8217;s implement the service class as an example.<\/p>\n<h3>Adding a Marker Attribute<\/h3>\n<p>We need to think about how we are going to choose which models we are going to generate service classes for. We can do this for all models in the project, but that would cause services to be generated even for the models we don&#8217;t need. For that, we can use a marker attribute. A marker attribute is a simple attribute that has no functionality and exists only to be located.<\/p>\n<p>We&#8217;re going to create a simple marker attribute, but we&#8217;re not going to define this attribute directly in the code. Instead, we will create a string containing C# code for the <code>[GenerateService]<\/code>\u00a0 attribute. We will have the generator automatically add this to the build of the consuming project and the attribute will be available at runtime. It is necessary to do this because when referencing our <code>Generator<\/code> project we set the <code>ReferenceOutputAssembly<\/code> to false.<\/p>\n<p>If <code>ReferenceOutputAssembly<\/code> is set to false, the output of the referenced project is not included as a <a href=\"https:\/\/learn.microsoft.com\/en-us\/visualstudio\/msbuild\/common-msbuild-project-items?view=vs-2022#reference\" target=\"_blank\" rel=\"nofollow noopener\" data-linktype=\"self-bookmark\">Reference<\/a> of this project, but it is still guaranteed that the other project builds before this one.<\/p>\n<p>Let&#8217;s create the attribute:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class SourceGenerationHelper\r\n{\r\n    public const string Attribute = \"\"\"\r\n        namespace Generator\r\n        {\r\n            [System.AttributeUsage(System.AttributeTargets.Class)]\r\n            public class GenerateServiceAttribute : System.Attribute\r\n            {\r\n            }\r\n        }\r\n        \"\"\";\r\n}<\/pre>\n<h3>Creating the Source Generator<\/h3>\n<p>As mentioned earlier, our starting point is a class that implements the <code>IIncrementalGenerator<\/code> interface and is decorated with the <code>[Generator]<\/code> attribute:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[Generator]\r\npublic sealed class ServiceGenerator : IIncrementalGenerator\r\n{\r\n    public void Initialize(IncrementalGeneratorInitializationContext context)\r\n    {\r\n        context.RegisterPostInitializationOutput(ctx =&gt; ctx.AddSource(\r\n            \"GenerateServiceAttribute.g.cs\",\r\n            SourceText.From(SourceGenerationHelper.Attribute, Encoding.UTF8)));\r\n    }\r\n}<\/pre>\n<p>In the implementation, we used the <code>RegisterPostInitializationOutput<\/code> method, which allows us to register a callback that will be called once. It&#8217;s useful for efficiently adding &#8220;constant&#8221; fonts to the build, like our marker attribute. Now we have the attribute available for use in our <code>SourceGeneratorInCSharp<\/code> project.<\/p>\n<h3>Development of the Generator Pipeline<\/h3>\n<p>Now we need to create a pipeline for filtering and transforming, which by design memorizes the results in each layer to avoid redoing the work if there are no changes:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[Generator]\r\npublic sealed class ServiceGenerator : IIncrementalGenerator\r\n{\r\n    public void Initialize(IncrementalGeneratorInitializationContext context)\r\n    {\r\n        context.RegisterPostInitializationOutput(ctx =&gt; ctx.AddSource(\r\n            \"GenerateServiceAttribute.g.cs\",\r\n            SourceText.From(SourceGenerationHelper.Attribute, Encoding.UTF8)));\r\n\r\n        IncrementalValuesProvider&lt;ClassDeclarationSyntax&gt; enumDeclarations = context.SyntaxProvider\r\n            .CreateSyntaxProvider(\r\n                predicate: static (s, _) =&gt; IsSyntaxTargetForGeneration(s),\r\n                transform: static (ctx, _) =&gt; GetTargetForGeneration(ctx));\r\n\r\n        IncrementalValueProvider&lt;(Compilation, ImmutableArray&lt;ClassDeclarationSyntax&gt;)&gt; compilationAndEnums\r\n                = context.CompilationProvider.Combine(enumDeclarations.Collect());\r\n\r\n        context.RegisterSourceOutput(compilationAndEnums,\r\n            (spc, source) =&gt; Execute(source.Item1, source.Item2, spc));\r\n        }\r\n}<\/pre>\n<p>\nIn the first stage of the pipeline, we use the <code>CreateSyntaxProvider<\/code> method to filter the input list. The predicate, <code>IsSyntaxTargetForGeneration<\/code>, provides a first layer of filtering. The transform, <code>GetTargetForGeneration<\/code>, is used just to transform the result of the first filtering.<\/p>\n<p>The next pipeline stage simply combines our collection of <code>ClassDeclarationSyntax<\/code> issued in the first stage with the current compilation.<\/p>\n<p>With that, we generate the source code using the custom <code>Execute<\/code> method.<\/p>\n<h3>Implementing the Stages<\/h3>\n<p>The <code>IsSyntaxTargetForGeneration<\/code> predicate is a method that will be called very often to check if the given <code>SyntaxNode<\/code> is relevant to our generator.<\/p>\n<p>Syntax nodes are one of the main elements of syntax trees. These nodes represent declarations, statements, clauses, and expressions. Each category of syntax nodes is represented by a separate class derived from <code>Microsoft.CodeAnalysis.SyntaxNode:<\/code><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public static bool IsSyntaxTargetForGeneration(SyntaxNode syntaxNode)\r\n{\r\n    return syntaxNode is ClassDeclarationSyntax classDeclarationSyntax &amp;&amp;\r\n        classDeclarationSyntax.AttributeLists.Count &gt; 0 &amp;&amp;\r\n        classDeclarationSyntax.AttributeLists\r\n            .Any(al =&gt; al.Attributes\r\n                .Any(a =&gt; a.Name.ToString() == \"GenerateService\"));\r\n}<\/pre>\n<p>In our implementation, we check if the <code>syntaxNode<\/code> object is an instance of the <code>ClassDeclarationSyntax<\/code> class and that it has an attribute with the name <code>\"GenerateService\"<\/code>.<\/p>\n<p>In the transformation stage, we must extract and return a syntax node of type <code>ClassDeclarationSyntax<\/code> from the given context:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public static ClassDeclarationSyntax GetTargetForGeneration(GeneratorSyntaxContext context)\r\n{\r\n    var classDeclarationSyntax = (ClassDeclarationSyntax)context.Node;\r\n\r\n    return classDeclarationSyntax;\r\n}<\/pre>\n<h3>Working With Templates<\/h3>\n<p>Before starting work on the <code>Execute<\/code> method, let&#8217;s create a template to use for code generation. A simple string builder would suffice, however, we can use a template engine. At this point, we can use the <a href=\"https:\/\/github.com\/scriban\/scriban\" target=\"_blank\" rel=\"nofollow noopener\">Scriban<\/a> template engine.<\/p>\n<p><code>Scriban<\/code>, which is a swift, robust, secure, and lightweight scripting language and engine designed for .NET. By adopting this approach, we can store the templates in individual files, thereby maintaining a well-organized solution.<\/p>\n<p>To use this template tool we need to install some packages. <span style=\"font-weight: 400;\">Let\u2019s inspect the content of the <code>Generator.csproj<\/code> file:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\" data-enlighter-highlight=\"4-6\">&lt;Project Sdk=\"Microsoft.NET.Sdk\"&gt;\r\n    &lt;ItemGroup&gt;\r\n        &lt;PackageReference Include=\"Microsoft.CodeAnalysis.CSharp.Workspaces\" \r\n            Version=\"4.6.0\" \r\n            PrivateAssets=\"all\" \/&gt;\r\n        &lt;PackageReference Include=\"Microsoft.CSharp\" Version=\"4.7.0\" \/&gt;\r\n        &lt;PackageReference Include=\"Scriban\" Version=\"5.7.0\" IncludeAssets=\"Build\"\/&gt;\r\n        &lt;PackageReference Include=\"System.Threading.Tasks.Extensions\" Version=\"4.5.4\" \/&gt;\r\n    &lt;\/ItemGroup&gt;\r\n&lt;\/Project&gt;<\/pre>\n<p>Now, let&#8217;s create a file named <code>Services.scriban<\/code> inside the <code>Templates<\/code> folder, with the content:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">using {{class_namespace}};\r\n\r\nnamespace {{class_assembly}}.Services \r\n{\r\n    public partial class {{class_name}}Service\r\n    {\r\n        private static readonly List&lt;{{class_name}}&gt; _list = new();\r\n\r\n        public virtual List&lt;{{class_name}}&gt; All()\r\n        {\r\n            return _list;\r\n        }\r\n\r\n        public virtual void Add({{class_name}} item)\r\n        {\r\n            _list.Add(item);\r\n        }\r\n\r\n        public virtual void Update({{class_name}} item)\r\n        {\r\n            var existing = _list.Single(x =&gt; x.Id == item.Id);\r\n\r\n            _list.Remove(existing);\r\n            _list.Add(item);\r\n        }\r\n\r\n        public virtual void Delete(int id)\r\n        {\r\n            var existing = _list.Single(x =&gt; x.Id == id);\r\n\r\n            _list.Remove(existing);\r\n        }\r\n    }\r\n}<\/pre>\n<p>Now, we need to mark the file as an embedded resource in <code class=\" language-text\">Generator.csproj<\/code> file:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;ItemGroup&gt;\r\n    &lt;None Remove=\"Templates\\**\\*.scriban\" \/&gt;\r\n    &lt;EmbeddedResource Include=\"Templates\\**\\*.scriban\" \/&gt;\r\n&lt;\/ItemGroup&gt;<\/pre>\n<h3>Development of Source Generators<\/h3>\n<p>After doing that, we can go back to our <code>Execute<\/code> method in <code>ServiceGenerator<\/code> and implement it:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public void Execute(Compilation compilation, \r\n    ImmutableArray&lt;ClassDeclarationSyntax&gt; classes, \r\n    SourceProductionContext context)\r\n{\r\n    foreach (var classSyntax in classes)\r\n    {\r\n        \/\/ Converting the class to a semantic model to access much more meaningful data.\r\n        var model = compilation.GetSemanticModel(classSyntax.SyntaxTree);\r\n\r\n        \/\/ Parse to declared symbol, so you can access each part of code separately,\r\n        \/\/ such as interfaces, methods, members, contructor parameters etc.\r\n        var symbol = model.GetDeclaredSymbol(classSyntax);\r\n\r\n        var className = symbol.Name;\r\n\r\n        if (!className.Contains(\"Model\"))\r\n        {\r\n            var error = Diagnostic.Create(DiagnosticsDescriptors.ClassWithWrongNameMessage,\r\n                classSyntax.Identifier.GetLocation(),\r\n                className);\r\n\r\n            context.ReportDiagnostic(error);\r\n\r\n            return;\r\n        }\r\n\r\n        var classNamespace = symbol.ContainingNamespace?.ToDisplayString();\r\n\r\n        var classAssembly = symbol.ContainingAssembly?.Name;\r\n\r\n        \/\/ Get the template string\r\n        var text = GetEmbededResource(\"Generator.Templates.Service.scriban\");\r\n\r\n        var template = Template.Parse(text);\r\n\r\n        var sourceCode = template.Render(new { \r\n            ClassName = className, \r\n            ClassNamespace = classNamespace, \r\n            ClassAssembly = classAssembly \r\n        });\r\n\r\n        context.AddSource(\r\n            $\"{className}{\"Service\"}.g.cs\",\r\n            SourceText.From(sourceCode, Encoding.UTF8)\r\n        );\r\n    }\r\n}<\/pre>\n<p>Inside the loop, we convert the class syntax node to a semantic model using the <code>Compilation.GetSemanticModel<\/code> method. The semantic model provides more detailed information about the code, allowing access to meaningful data such as interfaces, methods, members, and constructor parameters.<\/p>\n<p>After we use the <code>model.GetDeclaredSymbol<\/code> method to obtain the symbol for the class. A symbol represents a declared code element and provides information about its properties, including its name, containing namespace, and containing assembly.<\/p>\n<p>The <code>GetEmbededResource<\/code> method was called to retrieve the template string from an embedded resource.\u00a0<\/p>\n<p>We use the <code>Template.Parser<\/code> method to prepare our template for rendering and through the <code>Render<\/code> method we get our generated source code.<\/p>\n<p>Finally, the generated source code is added to the compilation using <code>context.AddSource<\/code>. The method takes a name for the generated file (constructed from the class name) and the source code is represented as <code>SourceText<\/code>.<\/p>\n<h3>Debugging Source Generators<\/h3>\n<p>When developing source generators, we often need to debug the generators themselves. Since these generators run during the build process, we can&#8217;t debug them like casual C# projects, so we have to debug them some other way. If we want to attach our debugger to the compiler, the generator will run so fast that we won&#8217;t have enough time for that. Then we can use another trick, we can just wait until the debugger is attached.<\/p>\n<p>At the beginning of the methods, add code to launch the debugger:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public void Execute(Compilation compilation, \r\n    ImmutableArray&lt;ClassDeclarationSyntax&gt; classes, \r\n    SourceProductionContext context)\r\n{\r\n    Debugger.Launch();\r\n    ...\r\n}\r\n<\/pre>\n<h3>Emitting Diagnostic Messages<\/h3>\n<p>Sometimes we may want to provide some diagnostic feedback to the developer to let them know when things aren&#8217;t going as expected. The context provided in the <code>Execute<\/code> method provides the <code>context.ReportDiagnostic<\/code> method, used to log diagnostic messages.<\/p>\n<p>A diagnostic entity requires a message, message type, title, diagnostic code, and help link. The location is optional to identify the exact location of the problem in the source code, and we can pass optional arguments for the descriptor.<\/p>\n<p>To keep things clean, we can store diagnostic descriptors in a separate static class:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public static class DiagnosticsDescriptors\r\n{\r\n    public static readonly DiagnosticDescriptor ClassWithWrongNameMessage\r\n        = new(\"ERR001\",                                        \/\/ id\r\n            \"Worng name\",                                      \/\/ title\r\n            \"The class '{0}' must be contains 'Model' prefix\", \/\/ message\r\n            \"Generator\",                                       \/\/ category\r\n            DiagnosticSeverity.Error,\r\n            true);\r\n}<\/pre>\n<p>To report a diagnostic message we just call <code>ReportDiagnostic<\/code> method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"5-14\">public void Execute(Compilation compilation, \r\n    ImmutableArray&lt;ClassDeclarationSyntax&gt; classes, \r\n    SourceProductionContext context)\r\n{\r\n    ...\r\n    if (!className.Contains(\"Model\"))\r\n    {\r\n        var error = Diagnostic.Create(DiagnosticsDescriptors.ClassWithWrongNameMessage,\r\n            classSyntax.Identifier.GetLocation(),\r\n            className);\r\n\r\n        context.ReportDiagnostic(error);\r\n\r\n        return;\r\n    }\r\n}<\/pre>\n<h3>Executing Source Generators<\/h3>\n<p>We&#8217;re done with the <code>Generator<\/code> project, so now let&#8217;s get it working.<\/p>\n<p>There is still no content in our <code>Analyzers<\/code> because we don&#8217;t use the <code>[GenerateService]<\/code> attribute, so we can&#8217;t generate any code. Let&#8217;s start by creating a new model with our attribute, called <code>PersonModel<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[GenerateService]\r\npublic class PersonModel\r\n{\r\n    public int Id { get; set; }\r\n\r\n    public string? Name { get; set; }\r\n}<\/pre>\n<p>The project needs to be built and upon completion, we will see the generated code in the Solution Explorer analyzer:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">using SourceGeneratorInCSharp.Models;\r\n\r\nnamespace SourceGeneratorInCSharp.Services \r\n{\r\n    public partial class PersonModelService\r\n    {\r\n        private static readonly List&lt;PersonModel&gt; _list = new();\r\n\r\n        public virtual List&lt;PersonModel&gt; All()\r\n        {\r\n            return _list;\r\n        }\r\n\r\n        public virtual void Add(PersonModel item)\r\n        {\r\n            _list.Add(item);\r\n        }\r\n\r\n        public virtual void Update(PersonModel item)\r\n        {\r\n            var existing = _list.Single(x =&gt; x.Id == item.Id);\r\n\r\n            _list.Remove(existing);\r\n            _list.Add(item);\r\n        }\r\n\r\n        public virtual void Delete(int id)\r\n        {\r\n            var existing = _list.Single(x =&gt; x.Id == id);\r\n\r\n            _list.Remove(existing);\r\n        }\r\n    }\r\n}<\/pre>\n<p>With the <code>PersonModelService<\/code> generated, let&#8217;s use:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">namespace SourceGeneratorInCSharp\r\n{\r\n    using Services;\r\n\r\n    public class Program\r\n    {\r\n        public static void Main(string[] args)\r\n        {\r\n            var personModelService = new PersonModelService();\r\n\r\n            personModelService.Add(new() { Id = 1, Name = \"Mathew\" });\r\n            personModelService.All().ForEach(x =&gt; Console.WriteLine(x.Name));\r\n        }\r\n    }\r\n}<\/pre>\n<h3>Testing Source Generators<\/h3>\n<p>Testing is a very important part of every developer process and as you might expect, writing code generators is no exception.<\/p>\n<p>Let&#8217;s create a <code>MsTest<\/code> project and add it to the current solution:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\">dotnet new mstest -o Tests\r\ndotnet sln add SourceGeneratorInCSharp<\/pre>\n<p>Before creating the test, we need to create a helper method that uses a <code>Roslyn<\/code> resource to perform the code compilation and return the generated output:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public static class Helper\r\n{\r\n    public static string GetGeneratedOutput(string sourceCode)\r\n    {\r\n        var syntaxTree = CSharpSyntaxTree.ParseText(sourceCode);\r\n\r\n        var references = AppDomain.CurrentDomain.GetAssemblies()\r\n            .Where(assembly =&gt; !assembly.IsDynamic)\r\n            .Select(assembly =&gt; MetadataReference.CreateFromFile(assembly.Location))\r\n            .Cast&lt;MetadataReference&gt;();\r\n\r\n        var compilation = CSharpCompilation.Create(\"SourceGeneratorTests\",\r\n            new[] { syntaxTree },\r\n            references,\r\n            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));\r\n\r\n        \/\/ Source Generator to test\r\n        var generator = new ServiceGenerator();\r\n\r\n        CSharpGeneratorDriver.Create(generator)\r\n            .RunGeneratorsAndUpdateCompilation(compilation, \r\n                out var outputCompilation, \r\n                out var diagnostics\r\n            );\r\n\r\n        return outputCompilation.SyntaxTrees.Skip(1).LastOrDefault()?.ToString();\r\n    }\r\n}<\/pre>\n<p>After that, we can create the test:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[TestClass]\r\npublic class SourceGeneratorsUnitTest\r\n{\r\n    [TestMethod]\r\n    public void WhenGeneratePersonModelService_ThenReturnCorrectOutput()\r\n    {\r\n        var input = \"\"\"\r\n            using Generator.Attributes;\r\n\r\n            namespace SourceGeneratorInCSharp.Models\r\n            {\r\n                [GenerateService]\r\n                public class PersonModel\r\n                {\r\n                    public int Id { get; set; }\r\n\r\n                    public string? Name { get; set; }\r\n                }\r\n            }\r\n            \"\"\";\r\n\r\n        var expectedResult = \"\"\"\r\n            using SourceGeneratorInCSharp.Models;\r\n\r\n            namespace SourceGeneratorTests.Services \r\n            {\r\n                public partial class PersonModelService\r\n                {\r\n                    private static readonly List&lt;PersonModel&gt; _list = new();\r\n\r\n                    public virtual List&lt;PersonModel&gt; All()\r\n                    {\r\n                        return _list;\r\n                    }\r\n\r\n                    public virtual void Add(PersonModel item)\r\n                    {\r\n                        _list.Add(item);\r\n                    }\r\n\r\n                    public virtual void Update(PersonModel item)\r\n                    {\r\n                        var existing = _list.Single(x =&gt; x.Id == item.Id);\r\n\r\n                        _list.Remove(existing);\r\n                        _list.Add(item);\r\n                    }\r\n\r\n                    public virtual void Delete(int id)\r\n                    {\r\n                        var existing = _list.Single(x =&gt; x.Id == id);\r\n\r\n                        _list.Remove(existing);\r\n                    }\r\n                }\r\n            }\r\n            \"\"\";\r\n\r\n        var output = Helper.GetGeneratedOutput(input);\r\n\r\n        Assert.AreEqual(expectedResult, output);\r\n    }\r\n}<\/pre>\n<p>After all of this, we can go ahead and explain some additional points.<\/p>\n<h2>Generating Using SyntaxFactory<\/h2>\n<p>Another approach to generating source code is using <code>SyntaxFactory<\/code>. It is located at <code>Microsoft.CodeAnalysis.CSharp<\/code>, and provides a comprehensive set of methods for creating syntax nodes and tokens, giving developers the means to programmatically generate C# code.<\/p>\n<p>We can rewrite the first example:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[Generator]\r\npublic sealed class ExampleGeneratorSyntaxFactory : IIncrementalGenerator\r\n{\r\n    public void Initialize(IncrementalGeneratorInitializationContext context)\r\n    {\r\n        context.RegisterPostInitializationOutput(ctx =&gt;\r\n        {\r\n            var classBlock = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName(\"SourceGeneratorInCSharp\"))\r\n                .AddMembers(\r\n                    SyntaxFactory.ClassDeclaration(\"SyntaxFactoryHelloWorld\")\r\n                    .AddModifiers(\r\n                        SyntaxFactory.Token(SyntaxKind.PublicKeyword),\r\n                        SyntaxFactory.Token(SyntaxKind.StaticKeyword)\r\n                    )\r\n                    .AddMembers(\r\n                        SyntaxFactory.MethodDeclaration(\r\n                            SyntaxFactory.ParseTypeName(\"void\"),\r\n                            \"SayHello\"\r\n                        )\r\n                        .AddModifiers(\r\n                            SyntaxFactory.Token(SyntaxKind.PublicKeyword),\r\n                            SyntaxFactory.Token(SyntaxKind.StaticKeyword)\r\n                        )\r\n                        .AddBodyStatements(\r\n                            SyntaxFactory.ExpressionStatement(\r\n                                SyntaxFactory.InvocationExpression(\r\n                                    SyntaxFactory.MemberAccessExpression(\r\n                                        SyntaxKind.SimpleMemberAccessExpression,\r\n                                        SyntaxFactory.IdentifierName(\"Console\"),\r\n                                        SyntaxFactory.IdentifierName(\"WriteLine\")\r\n                                    ))\r\n                                    .WithArgumentList(\r\n                                        SyntaxFactory.ArgumentList()\r\n                                            .AddArguments(\r\n                                                SyntaxFactory.Argument(\r\n                                                    SyntaxFactory.LiteralExpression(\r\n                                                        SyntaxKind.StringLiteralExpression,\r\n                                                        SyntaxFactory.Literal(\"Hello From Generator\")\r\n                                                    )\r\n                                                )\r\n                                            )\r\n                                    )\r\n                            )\r\n                        )\r\n                    )\r\n                ).NormalizeWhitespace();\r\n\r\n            ctx.AddSource(\"ExampleGeneratorSyntaxFactory.g\",\r\n                SourceText.From(classBlock.ToFullString(), Encoding.UTF8));\r\n        });\r\n    }\r\n}<\/pre>\n<p>As we can see, a lot of methods need to be used to generate even a simple scenario and we can\u2019t immediately see what the code will look like, without checking the results of the generation.<\/p>\n<h2>Emitting Compiler Generated files<\/h2>\n<p>By default, source generators do not produce artifacts directly. Instead, they generate additional source code during the compilation process, which is compiled along with the rest of the project source code, thus only being viewable through an IDE. This can be a problem, since for this type of file, we can&#8217;t do a code review.<\/p>\n<p>To enable persisting source generator files to the file system, we can set the <code>EmitCompilerGeneratedFiles<\/code> property in our <code>Console<\/code> project file:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;PropertyGroup&gt;\r\n    &lt;EmitCompilerGeneratedFiles&gt;true&lt;\/EmitCompilerGeneratedFiles&gt;\r\n&lt;\/PropertyGroup&gt;<\/pre>\n<p>By setting the property alone, the compiler will save the generated files to the disk. And then, we can see that the source-generated files are written to the <code>obj<\/code> folder:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExampleEmit.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-94699\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExampleEmit.png\" alt=\"Output compiled generated files from Source Generators in C#\" width=\"492\" height=\"387\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExampleEmit.png 492w, https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExampleEmit-300x236.png 300w\" sizes=\"auto, (max-width: 492px) 100vw, 492px\" \/><\/a><\/p>\n<p>This can be a problem as the <code>bin<\/code> and <code>obj<\/code>\u00a0folders are normally excluded from source control. We can specify the <code>CompilerGeneratedFilesOutputPath<\/code> property to determine the location of the compiler-emitted files. This property allows us to set a custom path relative to the project root folder:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;PropertyGroup&gt;\r\n    &lt;EmitCompilerGeneratedFiles&gt;true&lt;\/EmitCompilerGeneratedFiles&gt;\r\n    &lt;CompilerGeneratedFilesOutputPath&gt;Generated&lt;\/CompilerGeneratedFilesOutputPath&gt;\r\n&lt;\/PropertyGroup&gt;<\/pre>\n<p>This will write the files to the <code>Generated<\/code> folder in the project:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExampleCustomFolder-1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-94701\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExampleCustomFolder-1.png\" alt=\"Custom folder for files generated from Source Generators in c#\" width=\"440\" height=\"388\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExampleCustomFolder-1.png 440w, https:\/\/code-maze.com\/wp-content\/uploads\/2023\/07\/SourceGeneratorExampleCustomFolder-1-300x265.png 300w\" sizes=\"auto, (max-width: 440px) 100vw, 440px\" \/><\/a>\u00a0<\/p>\n<p>Now, when we try to build for a second time after the files have already been written, we get an error:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"powershell\">Error CS0111 Type 'HelloWorld' already defines a member called 'SayHello' with the same parameter types<\/code><\/p>\n<p>To resolve this issue, the solution is to remove the emitted files from the project compilation, by using a wildcard pattern to exclude all the .cs files in those folders:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;ItemGroup&gt;\r\n    &lt;!-- Exclude the output of source generators from the compilation --&gt;\r\n    &lt;Compile Remove=\"$(CompilerGeneratedFilesOutputPath)\/**\/*.cs\" \/&gt;\r\n&lt;\/ItemGroup&gt;<\/pre>\n<p>With this modification, the output of the source generator is now stored on the disk. This ensures it can be included in source control for easy review during pull requests. Also, and most importantly, it no longer affects the compilation process.<\/p>\n<h2>Use Cases<\/h2>\n<p>Source generators can be used for some common use cases including:<\/p>\n<ul>\n<li>Dependency Injection: We can use source generators to automatically generate code for dependency injection containers, reducing the boilerplate code needed to set up dependencies. They can also suppress the use of IoC\/DI containers.\n<\/li>\n<li>Data Access Layers: Source generators can help in generating data access, such as entity classes, and repositories based on models or database schema definitions.\n<\/li>\n<li>Builder pattern: Source generators can generate builder classes or fluent interfaces, allowing for more readable and expressive code when constructing complex objects.\n<\/li>\n<li>Code Analysis and Validation: Source generators can be used to analyze the code during compilation and enforce coding standards, ensuring that developers adhere to best practices and naming conventions.\n<\/li>\n<li>Automatic Tests Generation: Source generators can assist in automatically generating test cases or test data for unit testing. It saves time in writing repetitive test code.\n<\/li>\n<li>Code Annotations and Documentation: Source generators can create code annotations and inline documentation. This makes it easier for developers to understand and document the purpose and usage of various code elements.<\/li>\n<\/ul>\n<p>We can access a list of implemented source generators in <a href=\"https:\/\/github.com\/amis92\/csharp-source-generators\" target=\"_blank\" rel=\"nofollow noopener\">csharp-source-generators<\/a> GitHub repository.<\/p>\n<h2>Conclusion<\/h2>\n<p>In this article, we describe the basic concepts regarding code generators. Furthermore, through a simple example, we implement an <code>IIncrementalGenerator<\/code>.<\/p>\n<p>Using a more complex example, we can demonstrate how to filter objects by marker attributes, keeping performance in mind to ensure the generator&#8217;s consumers don&#8217;t suffer from IDE delays. It was also possible to implement feedback through diagnostic messages. Not least, we can see how it is possible to debug and test the generators.<\/p>\n<p>Regarding the generation of artifacts, we can see that it is possible to add our source codes generated in the source control, thus enabling the code review.<\/p>\n<p>Finally, we describe some use cases for code generators and provide a repository where we can find many of them.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Traditionally, code generation in C# involved using external tools or templates to generate code before the compilation process, like the T4 template. However, with source generators, code generation becomes an integral part of the compilation itself. In this article, we&#8217;ll explore the basics of C# source generators and how to use this powerful feature to [&hellip;]<\/p>\n","protected":false},"author":6,"featured_media":62189,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[12],"tags":[1811,1899],"class_list":["post-89800","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-csharp","tag-c","tag-source-generators","et-has-post-format-content","et_post_format-et-post-format-standard"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.7 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Source Generators in C#<\/title>\n<meta name=\"description\" content=\"In this article we are going to talk about Source Generators in C#. We will talk about the background and how to use it in a project.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/code-maze.com\/csharp-source-generators\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Source Generators in C#\" \/>\n<meta property=\"og:description\" content=\"In this article we are going to talk about Source Generators in C#. We will talk about the background and how to use it in a project.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/code-maze.com\/csharp-source-generators\/\" \/>\n<meta property=\"og:site_name\" content=\"Code Maze\" \/>\n<meta property=\"article:published_time\" content=\"2023-08-03T05:44:31+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-08-16T07:15:52+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1100\" \/>\n\t<meta property=\"og:image:height\" content=\"620\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Code Maze\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/CodeMazeBlog\" \/>\n<meta name=\"twitter:site\" content=\"@CodeMazeBlog\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Code Maze\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":[\"Article\",\"BlogPosting\"],\"@id\":\"https:\/\/code-maze.com\/csharp-source-generators\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/csharp-source-generators\/\"},\"author\":{\"name\":\"Code Maze\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/09d29b223012c8e94a68ba62861d0b04\"},\"headline\":\"Source Generators in C#\",\"datePublished\":\"2023-08-03T05:44:31+00:00\",\"dateModified\":\"2023-08-16T07:15:52+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/code-maze.com\/csharp-source-generators\/\"},\"wordCount\":2424,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/csharp-source-generators\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png\",\"keywords\":[\"C#\",\"Source Generators\"],\"articleSection\":[\"C#\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/code-maze.com\/csharp-source-generators\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/code-maze.com\/csharp-source-generators\/\",\"url\":\"https:\/\/code-maze.com\/csharp-source-generators\/\",\"name\":\"Source Generators in C#\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/code-maze.com\/csharp-source-generators\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/csharp-source-generators\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png\",\"datePublished\":\"2023-08-03T05:44:31+00:00\",\"dateModified\":\"2023-08-16T07:15:52+00:00\",\"description\":\"In this article we are going to talk about Source Generators in C#. We will talk about the background and how to use it in a project.\",\"breadcrumb\":{\"@id\":\"https:\/\/code-maze.com\/csharp-source-generators\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/code-maze.com\/csharp-source-generators\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/csharp-source-generators\/#primaryimage\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png\",\"width\":1100,\"height\":620,\"caption\":\"C# Development\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/code-maze.com\/csharp-source-generators\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/code-maze.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Source Generators in C#\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/code-maze.com\/#website\",\"url\":\"https:\/\/code-maze.com\/\",\"name\":\"Code Maze\",\"description\":\"Learn. Code. Succeed.\",\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/code-maze.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/code-maze.com\/#organization\",\"name\":\"Code Maze\",\"url\":\"https:\/\/code-maze.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"width\":3511,\"height\":3510,\"caption\":\"Code Maze\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/CodeMazeBlog\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/09d29b223012c8e94a68ba62861d0b04\",\"name\":\"Code Maze\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez-150x150.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez-150x150.png\",\"caption\":\"Code Maze\"},\"description\":\"This is the standard author on the site. Most articles are published by individual authors, with their profiles, but when several authors have contributed, we publish collectively as a part of this profile.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/company\/codemaze\/\",\"https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog\"],\"url\":\"https:\/\/code-maze.com\/author\/codemazecontributor\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Source Generators in C#","description":"In this article we are going to talk about Source Generators in C#. We will talk about the background and how to use it in a project.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/code-maze.com\/csharp-source-generators\/","og_locale":"en_US","og_type":"article","og_title":"Source Generators in C#","og_description":"In this article we are going to talk about Source Generators in C#. We will talk about the background and how to use it in a project.","og_url":"https:\/\/code-maze.com\/csharp-source-generators\/","og_site_name":"Code Maze","article_published_time":"2023-08-03T05:44:31+00:00","article_modified_time":"2023-08-16T07:15:52+00:00","og_image":[{"width":1100,"height":620,"url":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png","type":"image\/png"}],"author":"Code Maze","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/CodeMazeBlog","twitter_site":"@CodeMazeBlog","twitter_misc":{"Written by":"Code Maze","Est. reading time":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":["Article","BlogPosting"],"@id":"https:\/\/code-maze.com\/csharp-source-generators\/#article","isPartOf":{"@id":"https:\/\/code-maze.com\/csharp-source-generators\/"},"author":{"name":"Code Maze","@id":"https:\/\/code-maze.com\/#\/schema\/person\/09d29b223012c8e94a68ba62861d0b04"},"headline":"Source Generators in C#","datePublished":"2023-08-03T05:44:31+00:00","dateModified":"2023-08-16T07:15:52+00:00","mainEntityOfPage":{"@id":"https:\/\/code-maze.com\/csharp-source-generators\/"},"wordCount":2424,"commentCount":0,"publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"image":{"@id":"https:\/\/code-maze.com\/csharp-source-generators\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png","keywords":["C#","Source Generators"],"articleSection":["C#"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/code-maze.com\/csharp-source-generators\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/code-maze.com\/csharp-source-generators\/","url":"https:\/\/code-maze.com\/csharp-source-generators\/","name":"Source Generators in C#","isPartOf":{"@id":"https:\/\/code-maze.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/code-maze.com\/csharp-source-generators\/#primaryimage"},"image":{"@id":"https:\/\/code-maze.com\/csharp-source-generators\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png","datePublished":"2023-08-03T05:44:31+00:00","dateModified":"2023-08-16T07:15:52+00:00","description":"In this article we are going to talk about Source Generators in C#. We will talk about the background and how to use it in a project.","breadcrumb":{"@id":"https:\/\/code-maze.com\/csharp-source-generators\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/code-maze.com\/csharp-source-generators\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/csharp-source-generators\/#primaryimage","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png","width":1100,"height":620,"caption":"C# Development"},{"@type":"BreadcrumbList","@id":"https:\/\/code-maze.com\/csharp-source-generators\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/code-maze.com\/"},{"@type":"ListItem","position":2,"name":"Source Generators in C#"}]},{"@type":"WebSite","@id":"https:\/\/code-maze.com\/#website","url":"https:\/\/code-maze.com\/","name":"Code Maze","description":"Learn. Code. Succeed.","publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/code-maze.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/code-maze.com\/#organization","name":"Code Maze","url":"https:\/\/code-maze.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","width":3511,"height":3510,"caption":"Code Maze"},"image":{"@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/CodeMazeBlog"]},{"@type":"Person","@id":"https:\/\/code-maze.com\/#\/schema\/person\/09d29b223012c8e94a68ba62861d0b04","name":"Code Maze","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/person\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez-150x150.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez-150x150.png","caption":"Code Maze"},"description":"This is the standard author on the site. Most articles are published by individual authors, with their profiles, but when several authors have contributed, we publish collectively as a part of this profile.","sameAs":["https:\/\/www.linkedin.com\/company\/codemaze\/","https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog"],"url":"https:\/\/code-maze.com\/author\/codemazecontributor\/"}]}},"_links":{"self":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/89800","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/comments?post=89800"}],"version-history":[{"count":7,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/89800\/revisions"}],"predecessor-version":[{"id":94890,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/89800\/revisions\/94890"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media\/62189"}],"wp:attachment":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media?parent=89800"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/categories?post=89800"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/tags?post=89800"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}