2008-09-24 12 views
15

Considerando que el archivo de datos de depuración está disponible (PDB) y usando System.Reflection u otro marco similar como Mono.Cecil, cómo recuperar mediante programación el nombre del archivo fuente y el número de línea donde un tipo o un miembro de un tipo es declarado.¿Cómo obtener el nombre del archivo de origen y el número de línea de un miembro de tipo?

Por ejemplo, digamos que usted ha compilado este archivo en un conjunto:

C: \ MyProject \ Foo.cs

1: public class Foo 
2: { 
3:  public string SayHello() 
4:  { 
5:   return "Hello"; 
6:  } 
7: } 

Cómo hacer algo como:

MethodInfo methodInfo = typeof(Foo).GetMethod("SayHello"); 
string sourceFileName = methodInfo.GetSourceFile(); // ?? Does not exist! 
int sourceLineNumber = methodInfo.GetLineNumber(); // ?? Does not exist! 

sourceFileName contendría "C: \ MyProject \ Foo.cs" y sourceLineNumber igual a 3.

Actualización: System.Diagnostics.StackFrame es capaz de obtener esa información, pero solo en el ámbito de la pila de llamadas en ejecución actual. Significa que el método debe invocarse primero. Me gustaría obtener la misma información, pero sin invocar al miembro de tipo.

+0

hay una nueva API para que, sin necesidad de utilizar lector de AP más, ver mi respuesta –

Respuesta

7

al utilizar el lector de PDB proporcionada por el CCI Metadata Project, es posible extraer la ubicación del código de un miembro de tipo dado. Ver un ejemplo de implementación en el código fuente de la OSS Gallio Project.

+0

Yann, CCI sigue siendo una cosa, pero el Proyecto Gallio está cerrado. Su último código fuente se puede encontrar en GitHub (https://github.com/Gallio), pero no hay forma de saber a qué parte se refiere. ¿Podría considerar proporcionar aquí el código fuente o alguna indicación de a qué archivo se refiere la implementación a la que se refiere? –

1

es posible encontrar algo de ayuda con estos enlaces:

Getting file and line numbers without deploying the PDB files También encontraron esta siguiendo post

"Hola Marcos,

del Se le dará el número de línea de su código (en el archivo de origen ):

Dim CurrentStack As System.Diagnostics.StackTrace 
MsgBox (CurrentStack.GetFrame(0).GetFileLineNumber) 

En caso de que le interese, puede averiguar sobre la rutina en la que está , así como a todas las personas que llaman.

Public Function MeAndMyCaller As String 
    Dim CurrentStack As New System.Diagnostics.StackTrace 
    Dim Myself As String = CurrentStack.GetFrame(0).GetMethod.Name 
    Dim MyCaller As String = CurrentStack.GetFrame(1).GetMethod.Name 
    Return "In " & Myself & vbCrLf & "Called by " & MyCaller 
End Function 

Esto puede ser muy útil si quieres una rutina de error generalizado porque puede obtener el nombre de la persona que llama (que sería donde se produjo el error).

Saludos, Fergus MVP [botón Inicio de Windows, el diálogo Apagar] "

+2

Lamentablemente, StackTrace proporciona información sobre la pila de llamadas actual; y no sobre un miembro externo arbitrario. Me gustaría obtener la información sin ejecutar realmente el método. –

+0

Richard, el enlace busycode está roto. ¿Hay un enlace actualizado en alguna parte? –

12

Hasta método de la fecha:

private static void Log(string text, 
         [CallerFilePath] string file = "", 
         [CallerMemberName] string member = "", 
         [CallerLineNumber] int line = 0) 
{ 
    Console.WriteLine("{0}_{1}({2}): {3}", Path.GetFileName(file), member, line, text); 
} 

Nueva Framework API la que puebla argumentos (marcados con atributos especiales) en tiempo de ejecución, ver más en my answer to this SO question

+0

Solo disponible para .Net 4.5 Gran desventaja para proyectos corporativos. – Kobor42

+5

Creo que fundamentalmente malentendiste la pregunta. Mostró cómo obtener información sobre la persona que llama, pero la pregunta le pregunta cómo consultar esto para cualquier símbolo. Ver el comentario de Yann Trevin a la respuesta de Richard. –

1

Utilizando uno de los métodos explicados anteriormente, dentro del constructor de un atributo, puede proporcionar la ubicación de origen de todo, que puede tener un atributo, por ejemplo, una clase. Véase la siguiente clase de atributo:

sealed class ProvideSourceLocation : Attribute 
    { 
     public readonly string File; 
     public readonly string Member; 
     public readonly int Line; 
     public ProvideSourceLocation 
      (
      [CallerFilePath] string file = "", 
      [CallerMemberName] string member = "", 
      [CallerLineNumber] int line = 0) 
     { 
      File = file; 
      Member = member; 
      Line = line; 
     } 

     public override string ToString() { return File + "(" + Line + "):" + Member; } 
    } 


[ProvideSourceLocation] 
class Test 
{ 
    ... 
} 

El puede escribir por ejemplo:

Console.WriteLine(typeof(Test).GetCustomAttribute<ProvideSourceLocation>(true)); 

de salida será:

a:\develop\HWClassLibrary.cs\src\Tester\Program.cs(65): 
Cuestiones relacionadas