2011-09-27 5 views
1

저는 여러 프로젝트로 구성된 .NET 솔루션을 보유하고 있습니다. 이 프로젝트 중 하나가 논리적으로 기본 프로젝트이고 다른 모든 프로젝트가 보조라고 할 수 있습니다. 우리 팀은 그 다음 프로젝트를 구축하기로 결정했습니다. 기본 프로젝트는 어셈블리를 생성합니다 (이를 Primary로 참조). 다른 모든 프로젝트의 어셈블리는 보조 어셈블리이며 기본 어셈블리에 리소스로 포함됩니다.IMetaDataDispenser.OpenScope를 사용하여 포함 된 어셈블리의 메타 데이터에 액세스하는 방법?

주 프로젝트의 SourceCodeForExceptionHelper 클래스는 발생하는 모든 예외에서 PDB 파일을 사용하여 원본 소스 코드를 가져와야합니다. 이를 수행하기 위해 나는 here으로 묘사 된 접근법을 사용한다. 저의 개념 증명 프로젝트에서 올바르게 작동했습니다. 그러나 그 클래스를 실제 솔루션으로 옮기려고 할 때 문제가 발생했습니다 : IMetaDataDispenser.OpenScope 메서드는 어셈블리 파일의 경로에 대한 null 참조가 필요하지 않습니다. 확실하게, 나는 그들의 파일이 주축에 내장되어 있기 때문에 보조 어셈블리에 대한 언급이 없다. 그런 이유로 나는 ISymbolReader 타입의 객체를 생성 할 수없고 소스 코드를 읽을 수 없다. 어떻게 그 문제를 해결할 수 있습니까? 그건 그렇고, PDB 파일없이 2 차 어셈블리 만 포함하기 때문에 문제가 더욱 악화됩니다 (필요한 경우 수행 할 예정 임).

도움과 조언을 미리 보내 주셔서 감사합니다.

+0

OpenScope을 호출하기 전에 자원을 디스크의 실제 파일로 출력 할 수 없습니까 (캐시 메커니즘이 있으므로 다음에 빠릅니다). –

+0

@ Simon 답장을 보내 주셔서 감사합니다. 예, 저와 제 동료는 어셈블리와 pdb 파일을 주 어셈블리에 포함시키는 아이디어에 대해 논의했습니다. 그 후 우리는 필요할 때이 파일들의 복사본을 디스크에 저장할 수 있습니다. 그러나 우리는이 해결책이 조금 이상하다는 것에 동의했습니다. 또한 코드를 통해 독자가 왜 그렇게하는지 설명하기가 어려울 것입니다. 그래서 여기에 내 질문을 게시했습니다. –

답변

3

실제 파일에 의존하기 때문에 .NET Framework 기본 기능을 사용하여이 작업을 수행 할 수 있다고 생각하지 않습니다. 그러나 Mono Cecil 라이브러리를 사용하는 솔루션에는 심볼 판독기의 파일 경로 대신 입력 스트림을 사용하는 오버로드가 있으므로이 솔루션이 있습니다.

using System; 
using System.IO; 
using Mono.Cecil; 
using Mono.Cecil.Cil; 
using Mono.Cecil.Pdb; 

namespace TestPdb 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      // we use a Stream for the assembly 
      AssemblyDefinition asm; 
      using (FileStream asmStream = new FileStream("testpdb.exe", FileMode.Open, FileAccess.Read, FileShare.Read)) 
      { 
       asm = AssemblyDefinition.ReadAssembly(asmStream); 
      } 

      // we use a Stream for the PDB 
      using (FileStream symbolStream = new FileStream("testpdb.pdb", FileMode.Open, FileAccess.Read, FileShare.Read)) 
      { 
       asm.MainModule.ReadSymbols(new PdbReaderProvider().GetSymbolReader(asm.MainModule, symbolStream)); 
      } 

      TypeDefinition type = asm.MainModule.GetType("TestPdb.Program"); 

      foreach (MethodDefinition method in type.Methods) 
      { 
       Console.WriteLine("Method:" + method.Name); 
       foreach (Instruction ins in method.Body.Instructions) 
       { 
        Console.WriteLine(" " + ins); 
        if (ins.SequencePoint != null) 
        { 
         Console.WriteLine(" Url:" + ins.SequencePoint.Document.Url); 
         // see http://blogs.msdn.com/b/jmstall/archive/2005/06/19/feefee-sequencepoints.aspx 
         if (ins.SequencePoint.StartLine != 0xFEEFEE) 
         { 
          Console.WriteLine(" StartLine:" + ins.SequencePoint.StartLine + " StartColumn:" + ins.SequencePoint.StartColumn); 
          Console.WriteLine(" EndLine:" + ins.SequencePoint.EndLine + " EndColumn:" + ins.SequencePoint.EndColumn); 
         } 
         // etc... 
        } 
       } 
      } 
     } 
    } 
} 

참고 : 여기에

은 PDB 정보를 포함, 콘솔에의 IL 코드를 덤프 "TestPdb"라는 이름의 콘솔 응용 프로그램의 예입니다 만 PDB의에서 읽을 필요가 있기 때문에, 당신은 다시 컴파일 일부 바이트를 저장하기 위해 READ_ONLY 조건부 기호를 정의하는 Cecil 라이브러리 .DLL 버전을 사용할 필요없이 어셈블리에 Cecil 소스 코드를 직접 포함시킬 수도 있습니다.

+0

이 아이디어에 감사드립니다. 임베디드 어셈블리에 대한 스트림을 만들려고했습니다. 그 후 하드 드라이브에서 액세스 할 수있는 pdb 파일을 사용합니다. 그러나 TypeDefinition 객체의 생성에는 성공하지 못했습니다. 나는 그 코드를 더 가지고 놀려고 노력할 것이다. Btw, 내 원본 샘플에서 C# (IL이 아님)에서 실제 소스 코드를 검색 할 수 있습니다. 같은 일을하는 솔루션을 개선하기가 어렵습니까? Mono.Cecil은 문서가 너무 적기 때문에 해결책 자체는 물어 보지 않지만 관련 기사를 참조하십시오. –

+0

@ 키 키퍼 - TypeDefinition은 Mono Cecil의 일부입니다. C# 소스 코드를 얻으려면 샘플에서와 똑같습니다. SequencePoint에는 문서가 포함되어 있고 Url은 C# 소스 파일을 가리 킵니다. 동일한 StreamReader 원칙을 다시 사용하여 파일을 읽을 수 있습니다. –

+0

SequencePoint 클래스의 Document 및 Url 속성을 참조 해 주셔서 감사합니다. 그것은 일반적으로 잘 작동합니다. 그러나 소스 코드 파일을 옮길 때 (예 : URL 속성이 잘못된 위치를 가리킬 때) 문제가 발생했습니다. Url에 의해 참조되는 .cs 파일을 열지 않도록 원본 소스 코드에 액세스 할 수 있습니까? –

관련 문제