我正在研究从调试器评估用户表达式。我想在方法上下文中编译表达式,然后使用调试器注入IL代码。
是否可以编译表达式,其中包含从外部程序集到使用Roslyn的IL代码的非公共类/类字段?
我的'MyNamespace.dll'有公共类'Test'和私有方法'PrivateMethod',我想从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来完成吗?
P.S。 我知道,我可以使用System.Reflection获取非公共字段符号,但是如何编译表达式呢?
答案 0 :(得分:0)
如果某个成员是私有的,则无法使用其他类中的普通代码访问该成员。与罗斯林无关。
如果你真的需要访问另一个类中的私有成员,并且你完全理解为什么它可能不是一个好主意,访问它的代码必须使用反射。