【问题标题】:Roslyn: Compile expression with non-public fields from external assemblyRoslyn:使用来自外部程序集的非公共字段编译表达式
【发布时间】: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


    【解决方案1】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多