Page 23 - MSDN Magazine, May 2017
P. 23

Figure 8 The Result of the Invocation via Reflection of Roslyn-Generated Code
fails. It’s important to mention that the output assembly is a .NET Stan- dard Library, so compiling source text will succeed only if the code parsed with Roslyn relies on APIs that are included in .NET Standard.
Now let’s look at what happens if the compilation succeeds. The System.Runtime.Loader name- space, included in the same-named NuGet package you imported at the beginning of the article, exposes a singleton class called Assembly- LoadContext, which exposes a method called LoadFromAssem- blyPath. This method returns an instance of the Assembly class, which allows you to use Reflection to first get a reference to the Helper class, then to get a reference to the CalculateCircleArea method, which you can invoke by passing a value for the radius parameter. The MethodInfo.Invoke method
Executing Code: the Emit APIs
The Emit APIs allow for compiling source code into assemblies. Then, with Reflection you can invoke and execute code. The next example is a combination of code generation, emit and diagnostic detection. Add a new file called EmitDemo.cs to the project, then consider the code listing shown in Figure 7. As you can see, a SyntaxTree is generated from source text that defines a Helper class containing a static method that calculates the area of a circle. The goal is to produce a .dll from this class and execute the Calculate- CircleArea method, passing the radius as an argument.
In the first part, the code creates a new compilation that rep- resents a single, immutable invocation to the C# compiler. The CSharpCompilation object allows the creation of an assembly through its Create method, and WithOptions lets you specify what kind of output to produce, in this case DynamicallyLinkedLibrary. AddReferences is used to add any references your code might need; to accomplish this, you must supply a type that has the same ref- erences needed by your code. In this particular case, you simply need the same references on which the object type relies. With Get- TypeInfo().Assembly.Location you retrieve the assembly name for the reference, then MetadataReference.CreateFromFile creates a reference to the assembly inside the compilation. In the end, the syntax tree is added to the compilation with AddSyntaxTrees.
In the second part of the code, an invocation to CSharpCompi- lation.Emit attempts to produce the binary and returns an object of type EmitResult. The latter is very interesting: It exposes a Success property of type bool that indicates whether or not the compilation succeeded, and it also exposes a property called Diagnostics, which returns an immutable array of Diagnostic objects that can be very useful to understand why the compilation failed. In Figure 7, you can easily see how the Diagnostics property is iterated if the compilation msdnmagazine.com
receives null as the first argument because CalculateCircleArea is a static method; therefore, you don’t need to pass any type instance. If you now call the GenerateAssembly method from Main in Program. cs, you’ll see the result of this work, as demonstrated in Figure 8, where the result of the calculation is visible in the Debug Console.
As you can imagine, Emit APIs plus Reflection in .NET Core give you great power and flexibility, because you can generate, analyze and execute C# code regardless of the OS. In fact, all of the examples discussed in this article will certainly run not only on Windows, but also on macOS and most of the Linux distributions. Additionally, invoking code from a library can be accomplished using the Roslyn Scripting APIs, so you’re not limited to Reflection.
Wrapping Up
.NET Core allows you to write C# code to create cross-platform applications that run on multiple OSes and devices, and this is because compilers are cross-platform themselves. Roslyn, the .NET Compiler Platform, empowers the C# compiler on .NET Core and allows developers to leverage the rich code analysis APIs to per- form code generation, analysis and compilation. This implies that you can automate tasks by generating and executing code on the fly, analyze source text for code issues, and perform a large number of activities on source code—on Windows, macOS, and Linux. n
AlessAndro del sole has been a Microsoft MVP since 2008. Awarded MVP of the Year five times, he has authored many books, eBooks, instructional videos and articles about .NET development with Visual Studio. Del Sole works as a senior .NET developer, focusing on .NET and mobile app development, training and consulting. You can follow him on Twitter: @progalex.
ThAnks to the following Microsoft technical expert for reviewing this article: Dustin Campbell
May 2017 19


































































































   21   22   23   24   25