Page 22 - MSDN Magazine, May 2017
P. 22

Figure 6 Detecting Code Issues with the Diagnostic APIs
object, if any. Take a look at Figure 5, which offers an extended version of the ViewModelGeneration class. The code checks if the result of invoking GetDiagnostics contains any diagnostics. If not, the code generates the View Model class. If instead the
result contains a collection of diagnostics, the code shows information for each diagnostic and returns null. The Diagnostic class provides very granular information about each code issue; for example, the Id property returns a diagnostic id; the Get- Message method returns the full diagnostic message; GetLineSpan returns the diagnostic position in the source code; and the Severity property returns the diagnostic severity, such as Error, Warning or Information.
Now, if you introduce some intentional errors into the source text contained in the models vari- able, inside the GenerateSample- ViewModel method in Program.cs, and then run the application, you’ll be able to see how the C# compiler returns full details about every code issue. Figure 6 shows an example.
It’s worth noting that the C# compiler produces a syntax tree even if it contains diagnostics. Not only does this result in full fidelity with the source text, it also gives developers an option to fix those issues with new syntax nodes.
Figure 7 Compiling and Executing Code with Emit APIs and Reflection
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit;
namespace RoslynCore {
public static class EmitDemo {
public static void GenerateAssembly() {
const string code = @"using System; using System.IO;
namespace RoslynCore {
public static class Helper {
public static double CalculateCircleArea(double radius) {
return radius * radius * Math.PI; }
} }";
var tree = SyntaxFactory.ParseSyntaxTree(code); string fileName="mylib.dll";
// Detect the file location for the library that defines the object type var systemRefLocation=typeof(object).GetTypeInfo().Assembly.Location;
// Create a reference to the library
var systemReference = MetadataReference.CreateFromFile(systemRefLocation);
// A single, immutable invocation to the compiler
// to produce a library
var compilation = CSharpCompilation.Create(fileName)
.WithOptions(
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
.AddReferences(systemReference) .AddSyntaxTrees(tree);
string path = Path.Combine(Directory.GetCurrentDirectory(), fileName); EmitResult compilationResult = compilation.Emit(path);
if(compilationResult.Success) {
// Load the assembly Assembly asm =
AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
// Invoke the RoslynCore.Helper.CalculateCircleArea method passing an argument double radius = 10;
object result =
asm.GetType("RoslynCore.Helper").GetMethod("CalculateCircleArea").
Invoke(null, new object[] { radius });
Console.WriteLine($"Circle area with radius = {radius} is {result}");
} else {
foreach (Diagnostic codeIssue in compilationResult.Diagnostics) {
string issue = $"ID: {codeIssue.Id}, Message: {codeIssue.GetMessage()}, Location: {codeIssue.Location.GetLineSpan()},
Severity: {codeIssue.Severity}";
Console.WriteLine(issue); }
} }
} }
18 msdn magazine .NET Core


































































































   20   21   22   23   24