After my post first post on: Code Generation I decided to go a bit further, so today we’ll Create a class with .NET Core and Roslyn and write the output to the console.

Let’s see:

1. Create the application#


Open a command prompt and run

1    md roslyn.create.class
2    cd roslyn.create.class
3    dotnet new
4    dotnet restore
5    code .

2. Replace the contents of project.json#


Replace the contents on project.json file in order to include the references to: Microsoft.CodeAnalysis.CSharp and **Microsoft.CodeAnalysis.Compilers **

 1{
 2  "version": "1.0.0-*",
 3  "buildOptions": {
 4    "debugType": "portable",
 5    "emitEntryPoint": true
 6  },
 7  "dependencies": {
 8    "Microsoft.CodeAnalysis.CSharp": "2.0.0-rc4",
 9    "Microsoft.CodeAnalysis.Compilers": "2.0.0-rc4"
10  },
11  "frameworks": {
12    "netcoreapp1.1": {
13      "dependencies": {
14        "Microsoft.NETCore.App": {
15          "type": "platform",
16          "version": "1.1.0"
17        }
18      },
19      "imports": "dnxcore50"
20    }
21  }
22}

3. Replace the contents of Program.cs#


The CreateClass method is where the magic occurs. Each relevant line is explained to help you understand each step.

 1using System;
 2using Microsoft.CodeAnalysis;
 3using Microsoft.CodeAnalysis.CSharp;
 4
 5namespace Roslyn.CodeGeneration
 6{
 7    public class Program
 8    {
 9        public static void Main(string[] args)
10        {
11            // Create a class
12            CreateClass();
13
14            // Wait to exit.
15            Console.Read();
16        }
17
18        /// <summary>
19        /// Create a class from scratch.
20        /// </summary>
21        static void CreateClass()
22        {
23            // Create a namespace: (namespace CodeGenerationSample)
24            var @namespace = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName("CodeGenerationSample")).NormalizeWhitespace();
25
26             // Add System using statement: (using System)
27            @namespace = @namespace.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("System")));
28
29            //  Create a class: (class Order)
30            var classDeclaration = SyntaxFactory.ClassDeclaration("Order");
31
32            // Add the public modifier: (public class Order)
33            classDeclaration = classDeclaration.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword));
34
35            // Inherit BaseEntity<T> and implement IHaveIdentity: (public class Order : BaseEntity<T>, IHaveIdentity)
36            classDeclaration = classDeclaration.AddBaseListTypes(
37                SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName("BaseEntity<Order>")),
38                SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName("IHaveIdentity")));
39
40            // Create a string variable: (bool canceled;)
41            var variableDeclaration = SyntaxFactory.VariableDeclaration(SyntaxFactory.ParseTypeName("bool"))
42                .AddVariables(SyntaxFactory.VariableDeclarator("canceled"));
43
44            // Create a field declaration: (private bool canceled;)
45            var fieldDeclaration = SyntaxFactory.FieldDeclaration(variableDeclaration)
46                .AddModifiers(SyntaxFactory.Token(SyntaxKind.PrivateKeyword));
47
48            // Create a Property: (public int Quantity { get; set; })
49            var propertyDeclaration = SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName("int"), "Quantity")
50                .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
51                .AddAccessorListAccessors(
52                    SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
53                    SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)));
54
55            // Create a stament with the body of a method.
56            var syntax = SyntaxFactory.ParseStatement("canceled = true;");
57
58            // Create a method
59            var methodDeclaration = SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), "MarkAsCanceled")
60                .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
61                .WithBody(SyntaxFactory.Block(syntax));
62
63            // Add the field, the property and method to the class.
64            classDeclaration = classDeclaration.AddMembers(fieldDeclaration, propertyDeclaration, methodDeclaration);
65
66            // Add the class to the namespace.
67            @namespace = @namespace.AddMembers(classDeclaration);
68
69            // Normalize and get code as string.
70            var code = @namespace
71                .NormalizeWhitespace()
72                .ToFullString();
73
74            // Output new code to the console.
75            Console.WriteLine(code);
76        }
77    }
78}

4. Run the application#


1    dotnet restore
2    dotnet run

The output should read:

 1namespace CodeGenerationSample
 2{
 3    using System;
 4
 5    public class Order : BaseEntity<Order>, IHaveIdentity
 6    {
 7        private bool canceled;
 8        public int Quantity
 9        {
10            get;
11            set;
12        }
13
14        public void MarkAsCanceled()
15        {
16            canceled = true;
17        }
18    }
19}

Get a copy of the code here: https://github.com/cmendible/dotnetcore.samples/tree/main/roslyn.create.class

Hope it helps!

Learn More#

Cross-Platform Code Generation with Roslyn and .NET Core