【发布时间】:2017-07-07 14:52:03
【问题描述】:
我正在从调试器评估用户表达式。我想在方法上下文中编译表达式,然后用调试器注入 IL 代码。
是否可以使用 Roslyn 编译包含从外部程序集到 IL 代码的非公共类/类字段的表达式?
我有带有公共类“Test”和私有方法“PrivateMethod”的“MyNamespace.dll”,我想从 Roslyn 编译中调用它。 我正在尝试使用下一个代码:
public class TestCompilationOptions
{
public void Test()
{
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "Output.dll");
Console.WriteLine("Preparing syntax tree");
string expressionString = @"
using System;
class XXX
{
public static void Main()
{
Console.WriteLine(MyNamespace.Test.PrivateMethod(2));
}
}";
//SyntaxTree targetTree = SyntaxFactory.ParseSyntaxTree(expressionString);
SyntaxTree targetTree = CSharpSyntaxTree.ParseText(expressionString);
Console.WriteLine("Preparing metadata references");
Assembly[] assemblys = new Assembly[4];
assemblys[0] = typeof(MyNamespace.Test).Assembly;
assemblys[1] = typeof(Console).Assembly;
assemblys[2] = typeof(object).Assembly;
assemblys[3] = Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), "System.Runtime.dll"));
MetadataReference[] metadataReferences = MetadataFromAssembly(assemblys);
Console.WriteLine("Preparing default namespaces");
IEnumerable<string> DefaultNamespaces = new[] {"System", "System.Runtime"};
Console.WriteLine("Preparing compilation options");
CSharpCompilationOptions ReleaseDll = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release);
CSharpCompilationOptions cOptions = ReleaseDll.WithUsings(DefaultNamespaces);
//.WithMetadataImportOptions(MetadataImportOptions.All);
Console.WriteLine("Getting compilation");
CSharpCompilation compilation = CSharpCompilation.Create("Output.dll", new SyntaxTree[] {targetTree}, metadataReferences, cOptions);
Console.WriteLine("Emitting compilation");
using (var dll = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
var emitRes = compilation.Emit(dll);
if (!emitRes.Success)
{
Console.WriteLine("Emited unsuccessfully!");
foreach (var d in emitRes.Diagnostics)
Console.WriteLine(d.ToString());
return;
}
}
}
public unsafe MetadataReference[] MetadataFromAssembly(Assembly[] assemblys)
{
MetadataReference[] result = new MetadataReference[assemblys.Length];
byte *b;
int length;
for (int i = 0; i < assemblys.Length; i++)
{
if (assemblys[i].TryGetRawMetadata(out b, out length))
{
var moduleMetadata = ModuleMetadata.CreateFromMetadata((IntPtr) b, length);
var assemblyMetadata = AssemblyMetadata.Create(moduleMetadata);
result[i] = assemblyMetadata.GetReference();
}
else
{
return null;
}
}
return result;
}
出现以下错误:
(8,44): error CS0117: 'Test' does not contain a definition for 'privateMember'
我在 Roslyn 和未注释行中公开了“WithMetadataImportOptions”和“MetadataImportOptions”
//.WithMetadataImportOptions(MetadataImportOptions.All);
然后出现以下错误:
(8,44): error CS0122: 'Test.privateMember' is inaccessible due to its protection level
那么是否可以使用一些 Roslyn API 来完成?
附: 我知道,我可以使用 System.Reflection 获取非公共字段符号,但是我该如何编译表达式呢?
【问题讨论】:
标签: c# .net compilation roslyn