Roslyn:使用外部程序集

时间:2017-07-07 14:52:04

标签: c# .net compilation roslyn

我正在研究从调试器评估用户表达式。我想在方法上下文中编译表达式,然后使用调试器注入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获取非公共字段符号,但是如何编译表达式呢?

1 个答案:

答案 0 :(得分:0)

如果某个成员是私有的,则无法使用其他类中的普通代码访问该成员。与罗斯林无关。

如果你真的需要访问另一个类中的私有成员,并且你完全理解为什么它可能不是一个好主意,访问它的代码必须使用反射。