Using Microsoft Roslyn

Microsoft Roslyn is an API that exposes the C# compiler as a service or one can say now the entire compiler is exposed in a form of a library that can be included in your project or application, earlier you needed to write code in C# and build that code, if it is successful then you get the compiled code in the form of an assembly, but now you can actually build or compile the code dynamically from within your .Net applications. You can now have Build process information or compile process information that was not available earlier. So now you can pass in your code as a string to the API and it will provide you with the code in Intermediate Language (IL) with syntactic and semantic information regarding your code. So the major advantage we get is one can do the Code Analysis using Roslyn.

Roslyn has nothing to do with the CLR, Roslyn can do the same for you as any other compiler can do, that is it can compile your code and return it in Intermediate Language that can then be passed to the CLR (as we know the CLR doesn't understand any specific language like C# or VB, so the role of every language compiler (.Net Compliant Language) is to produce a code in IL that is very well understood by the CLR).

With the introduction of Roslyn (Right now Roslyn is available a Community Technology Preview) now the compilers are no more the blackbox (that earlier takes in the code writhen in a managed language and outputs it as an assembly), now one can get the entire Syntax Tree of the code in the form of objects (API(s) are exposed to get the Syntax Tree).

One of the major advantages that I see now is that you can produce code from a User Interface, in other words suppose your application is in production and now you need to write some code, earlier you need to do the code changes and build the code again but now you can create a User Interface in your application (the UI can have a textarea and a button) and you can actually write the code on the UI and get it compiled at runtime without doing the deployment again. But yes you need to make your application intelligent enough.

Roslyn API(s) are available as NuGet Packages; you can do something anytime, so one can install it very easily by the Package Manager.

Here is a sample code showing some of the features of the Roslyn C# compiler.

First of all you need the Roslyn Libraries available as a NuGet Package that can be installed using the Package Manager in Visual Studio. For installing the Roslyn libraries, just open the Package Manager console and type in the following command:

PM> Install-Package Roslyn.Compilers.Common

Once the installation is successful, create a sample console application or a Web Application as needed and add the reference to the two libraries, that you got from the preceding installation. The two libraries are:

Roslyn.Compilers
Roslyn.Compilers.CSharp

And you are ready to go.

First we will see how to output the Syntax Tree or the code as the DLL. You can find the details of what the code does as inline comments within the code.

using System;

using System.IO;

using Roslyn.Compilers;

using Roslyn.Compilers.CSharp;

 

namespace SampleApplication

{

    class Program

    {

        static void Main(string[] args)

        {

 

            //Syntax tree is the code you want to compile at runtime

            var syntaxTree = SyntaxTree.ParseText(@"using System;

                class TestClass

                {

                    static void Main()

                    {

                        Console.WriteLine(""Testing Rolyn"");

                        Console.ReadLine();

                    }

                }");

 

            //Creates the copimlation, Here we are setting that compile it to a dll for the syntax tree defined above, adding references at runtime, here we are adding metadata

            //reference of System library at runtime

            var compilation = Compilation.Create("RoslynSampleApplication.dll",

                references: new[]

                {

                    new MetadataFileReference(typeof(object).Assembly.Location)

                },

                syntaxTrees: new[] { syntaxTree });

 

            //Here we are getting the Diagnostic results for a particular syntax tree on copilation, so if there are any errors we will get a list of that errors which can be

            //used to show it to user, These errors are just the same as we see in the Error list of Visual Studio.

            var diagnostics = compilation.GetDiagnostics();

 

            //Here i am prinitng the errors if any

            foreach (var diagnostic in diagnostics)

            {

                //You can also get the line number here on which the error has occurred. Code goes something like this: diagnostic.Location.GetLineSpan(usePreprocessorDirectives: true).StartLinePosition.Line

                Console.WriteLine("Error: {0}", diagnostic.Info.GetMessage());

            }

 

            //If we want to generate a DLL for the above syntax tree we can emit the compilation to a DLL by the following code.

            EmitResult result;

            using (var file = new FileStream("RoslynSampleApplication.dll", FileMode.Create))

            {

                result = compilation.Emit(file);

            }

        }

    }

}

The sample code I provided above does not have any errors, if you want to see some errors that are caught by the compilation diagnostic then you can make some invalid changes in the Syntax Tree and you will see the errors in the console window.
The DLL created above can now be consumed in the application. So this is how you can create DLL(s) at runtime. Now let's see how to write a piece of code at runtime, compile it and produce the output:
 

//Syntax tree is the code you want to compile at runtime

            var syntaxTree = SyntaxTree.ParseText(@"using System;

                class TestClass

                {

                    public static string GetWelcomeMessage()

                    {

                        return ""Welcome! Abhishek Jain"";

                    }

                }");

 

            //Creates the copimlation, Here we are setting that compile it to a dll for the syntax tree defined above, adding references at runtime, here we are adding metadata

            //reference of System library at runtime

            var compilation = Compilation.Create("RoslynSampleApplication.dll",

                options: new CompilationOptions(outputKind: OutputKind.DynamicallyLinkedLibrary),

                references: new[]

                {

                    new MetadataFileReference(typeof(object).Assembly.Location)

                },

                syntaxTrees: new[] { syntaxTree });

 

            //Here we are getting the Diagnostic results for a particular syntax tree on copilation, so if there are any errors we will get a list of that errors which can be

            //used to show it to user, These errors are just the same as we see in the Error list of Visual Studio.

            var diagnostics = compilation.GetDiagnostics();

 

            //Here i am printng the errors if any

            foreach (var diagnostic in diagnostics)

            {

                //var lineSpan = diagnostic.Location.GetLineSpan(usePreprocessorDirectives: true);

                //var startLine = lineSpan.StartLinePosition.Line;

                Console.WriteLine("Error: {0}", diagnostic.Info.GetMessage());

            }

 

            //Here the compiled code is emitted into memory stream which is used to create a assembly at runtime, and we are using this assembly at runtime only to invoke a

            //method present in one of the class of this assembly.

            Assembly assembly;

            using (var stream = new MemoryStream())

            {

                EmitResult emitResult = compilation.Emit(stream);

                assembly = Assembly.Load(stream.GetBuffer());

            }

 

            //Type of class is retrieved and for that type, method is retrieved from it using reflection, Method is invoked also by using reflection

            Type testClass = assembly.GetType("TestClass");

            MethodInfo methodInfo = testClass.GetMethod("GetWelcomeMessage");

            string welcomeMessage = methodInfo.Invoke(null, null).ToString();

 

            Console.WriteLine(welcomeMessage);

            Console.ReadLine();

So these are the very basic samples, I am also attaching the source code, if needed you can also try at your end.
 


Similar Articles