I'm trying to support C# code snippets with Roslyn but I can't seem to get it to work. It all compiles and runs but it only seems to run the first line??? Here's an example I put together to show the behavior:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using RoslynTest;
using System.Reflection;
string code = @"
Console.WriteLine(""Line 1"");
Console.WriteLine(""Line 2"");
Console.WriteLine(""Line 3"");
";
var compileUnit = SyntaxFactory.CompilationUnit();
var codeNamespace = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName("RoslynTest"));
compileUnit = compileUnit.AddUsings(
SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("System"))
);
var testClass = SyntaxFactory.ClassDeclaration("TestClass");
testClass = testClass.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword));
testClass = testClass.AddBaseListTypes(SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName("ITest")));
var testMethod = SyntaxFactory.MethodDeclaration(
SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)), "Test")
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
.WithBody(SyntaxFactory.Block(SyntaxFactory.ParseStatement(code)).NormalizeWhitespace());
testClass = testClass.AddMembers(testMethod);
codeNamespace = codeNamespace.AddMembers(testClass);
compileUnit = compileUnit.AddMembers(codeNamespace);
var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location);
var references = AppDomain.CurrentDomain
.GetAssemblies()
.Where(a => !a.IsDynamic)
.Select(a => a.Location)
.Where(s => !string.IsNullOrEmpty(s))
.Select(s => MetadataReference.CreateFromFile(s))
.ToList();
references.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "mscorlib.dll")));
references.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.dll")));
references.Add(MetadataReference.CreateFromFile(Path.Combine(assemblyPath, "System.Core.dll")));
var compilation = CSharpCompilation.Create(
assemblyName: Guid.NewGuid().ToString(),
syntaxTrees: new[] { compileUnit.SyntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release)
);
var stream = new MemoryStream();
var emitResult = compilation.Emit(stream);
if (emitResult.Success)
{
stream.Seek(0, SeekOrigin.Begin);
Assembly assembly = Assembly.Load(stream.ToArray());
Type type = assembly.GetType("RoslynTest.TestClass");
ITest test = Activator.CreateInstance(type) as ITest;
test.Test();
}
Basically, the class I generate implements an Interface called ITest and then runs the Test() method. If you look at the code snippet it should output 3 lines, however the output is always just a single line that says
Line 1.
CodePudding user response:
SyntaxFactory.Block(SyntaxFactory.ParseStatement(code))
ParseStatement is exactly that: it parses the first statement and ignores the rest.