2017-07-07 12 views
1

私はデバッガからのユーザー式の評価に取り組んでいます。私はメソッドコンテキストで式をコンパイルし、デバッガでILコードを注入したいと思っています。Roslyn:外部アセンブリから非公開フィールドで式をコンパイル

外部アセンブリから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; 
    } 

そして、次のエラーました:私は 'WithMetadataImportOptions' と 'MetadataImportOptions' Roslynの内部公衆とuncomenntedライン

作った

(8,44): error CS0117: 'Test' does not contain a definition for 'privateMember' 

//.WithMetadataImportOptions(MetadataImportOptions.All); 

エラーが発生しました:

(8,44): error CS0122: 'Test.privateMember' is inaccessible due to its protection level 

Roslyn APIを使用している可能性がありますか?

P.S. System.Reflectionを使用して非公開のフィールドシンボルを取得できますが、式をコンパイルするにはどうすればよいですか?

答えて

0

メンバーがプライベートである場合、別のクラスの通常のコードでメンバーにアクセスすることはできません。特にロザリンとは関係ありません。

本当に実際に別のクラスのプライベートメンバーにアクセスする必要があり、それが良い考えではない理由を完全に理解している場合は、アクセスするコードでリフレクションを使用する必要があります。

関連する問題