2008-09-24 15 views
15

Berücksichtigt, dass die Debug-Datendatei verfügbar ist (PDB) und entweder System.Reflection oder ein anderes ähnliches Framework wie Mono.Cecil, wie programmgesteuert den Quelldateinamen und die Zeilennummer, wo ein Typ oder Ein Member eines Typs wird deklariert.Wie erhält man den Quelldateinamen und die Zeilennummer eines Typmembers?

Zum Beispiel, sagen wir, Sie diese Datei in eine Assembly kompiliert haben:

C: \ MyProject \ Foo.cs

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

Wie aus wie etwas tun:

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

sourceFileName würde "C: \ MyProject \ Foo.cs" und sourceLineNumber gleich 3 enthalten.

Update: System.Diagnostics.StackFrame ist in der Tat in der Lage, diese Informationen zu erhalten, aber nur im Rahmen der aktuellen Ausführung von Call-Stack. Dies bedeutet, dass die Methode zuerst aufgerufen werden muss. Ich möchte die gleichen Informationen erhalten, aber ohne den Typ Mitglied aufzurufen.

+0

es neue API für das heißt, keine Notwendigkeit zu verwenden PDB Leser mehr, siehe meine Antwort –

Antwort

7

der PDB-Leser von den CCI Metadata Project bereitgestellt durch die Verwendung ist es möglich, den Code Ort eines bestimmten Typs Element zu extrahieren. Siehe eine beispielhafte Implementierung im Quellcode der OSS Gallio Project.

+0

Yann, CCI ist immer noch eine Sache, aber das Gallio Projekt ist stillgelegt. Der letzte Quellcode kann auf GitHub (https://github.com/Gallio) gefunden werden, aber es gibt keine Möglichkeit zu sagen, auf welchen Teil davon Sie sich beziehen. Könnten Sie in Erwägung ziehen, hier einen Quellcode anzugeben oder einen Hinweis darauf, in welcher Datei sich die Implementierung befindet, auf die Sie sich beziehen? –

1

Sie Hilfe mit diesen Links finden:

Getting file and line numbers without deploying the PDB files fand auch dieses folgende post

„Hallo Markus,

Nachfolgend erhalten Sie die Zeilennummer des Codes geben (in die Quelldatei):

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

Wenn Sie interessiert sind, können Sie sich über die Routine informieren, die Sie in, sowie alle Anrufer sind.

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 

Dies kann sehr nützlich sein, wenn Sie eine allgemeine Fehlerroutine wollen, weil es den Namen des Anrufers bekommen (was wäre, wo der Fehler aufgetreten ist).

Grüße, Fergus MVP [Windows-Schaltfläche Start, Shutdown Dialog] "

+2

Leider bietet StackTrace Informationen über den aktuellen Aufrufstack; und nicht über ein willkürliches äußeres Mitglied. Ich möchte die Informationen erhalten, ohne die Methode auszuführen. –

+0

Richard, der Busycode-Link ist kaputt. Gibt es irgendwo einen aktualisierten Link? –

12

AskGamblers Methode:

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); 
} 

New Framework API die Argumente (markiert mit speziellen Attributen) zur Laufzeit auffüllt, sehen Sie mehr in my answer to this SO question

+0

Nur für .Net 4.5 verfügbar. Großer Nachteil für Unternehmensprojekte. – Kobor42

+5

Ich denke, Sie haben die Frage grundlegend falsch verstanden. Sie haben gezeigt, wie Sie Informationen über den Anrufer erhalten, aber die Frage stellt sich die Frage, wie Sie dies für ein beliebiges Symbol abfragen können. Siehe Yann Trevins Kommentar zu Richards Antwort. –

1

Mit Hilfe eines der Verfahren, die oben erläutert wurde, innerhalb des Konstruktors eines Attributs können Sie den Quellort von allem angeben, der ein Attribut haben kann - zum Beispiel eine Klasse. Siehe die folgende Attributklasse:

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 
{ 
    ... 
} 

Die Sie zum Beispiel schreiben:

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

Ausgang wird sein:

a:\develop\HWClassLibrary.cs\src\Tester\Program.cs(65): 
Verwandte Themen