Microsoft Roslyn is an API which exposes C# compiler as a
service or one can say now the whole compiler is exposed in a form of a library
which can be included in your project or application, earlier you used to write
code in c# and build that code, if it is successful you get the compiled code
in the form of 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 which was not available earlier. So
now you can pass in your code as 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 with the help of Roslyn.
Roslyn has nothing to do with the CLR, Roslyn can do same
for you as any other compiler can do, that is it can compile your code and
return it in Intermediate Language which can then be passed to CLR (As we know
CLR don’t understand any particular language like C# or VB, so the role of
every language compiler (.Net Compliant Language) is to produce a code in IL
which is very well understood by the CLR)
With introduction of Roslyn (Right now Roslyn is available a
Community Technology Preview) now the compilers are no more the blackbox (which
earlier takes in the code writhen in managed language and outputs it as an
assembly), now one can get the entire Syntax tree of the code in the form of object
(API(s) are exposed to get the Syntax tree).
One of the major advantage which I see now is that you can
produce code from User interface, it means that suppose your application is in
Production environment 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 (UI can have a textarea and a button) and you can
actually write code on UI and get it compiled at runtime without doing the
deployment again. But yes you have to make your application intelligent enough.
Roslyn API(s) are available as NuGet Packages; you can
anytime, so one can install it very easily by Package manager.
Here is a sample code showing some of the features of Roslyn
C# compiler.
First of all you need Roslyn Libraries which are available
as NuGet Package which can be installed with the help of Package Manager in
.Net Visual Studio. For Installing a 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 per your need and add the reference to the
two libraries, which you have got from the above installation. Two libraries
are:
Roslyn.Compilers
Roslyn.Compilers.CSharp
And you are ready to go.
Firstly we will see how to output the syntax tree or the
code as the DLL. You can find the details of what the code do 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 which are caught by the Compilation diagnostic,
you can make some invalid changes in the Syntax tree and you can see the errors
in the console window.
The DLL created above can now be consumed in the
application. So this the way in which 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();
No comments:
Post a Comment