Comment obtenir le numéro de ligne actuel?


118

Voici un exemple de ce que je veux faire:

MessageBox.Show("Error line number " + CurrentLineNumber);

Dans le code au-dessus de CurrentLineNumber, devrait être le numéro de ligne dans le code source de ce morceau de code.

Comment puis je faire ça?


Vous ne pouvez pas faire cela de manière fiable , car le compilateur JIT peut faire des optimisations (par exemple du code en ligne), ce qui signifie que vos numéros de ligne seront faux.
adrianbanks

1
Puisque vous pouvez désactiver l'optimisation si vous le souhaitez, vous pouvez le faire de manière fiable.
jwg

Réponses:


176

Dans .NET 4.5 / C # 5, vous pouvez demander au compilateur de faire ce travail pour vous, en écrivant une méthode utilitaire qui utilise les nouveaux attributs de l'appelant:

static void SomeMethodSomewhere()
{
    ShowMessage("Boo");
}
...
static void ShowMessage(string message,
    [CallerLineNumber] int lineNumber = 0,
    [CallerMemberName] string caller = null)
{
     MessageBox.Show(message + " at line " + lineNumber + " (" + caller + ")");
}

Cela affichera, par exemple:

Boo à la ligne 39 (SomeMethodSomewhere)

Il y a aussi [CallerFilePath]qui vous indique le chemin du fichier de code d'origine.


Merci beaucoup pour la réponse. est-ce possible d'apprendre aussi le nom de l'objet? oh j'ai confondu avec autre chose. ce que je me demande, c'est le site asp.net 4.5. capteur d'erreur global. attraper l'erreur causée nom de l'objet?
MonsterMMORPG

@MonsterMMORPG non; juste les 3 que j'ai mentionnés ci-dessus
Marc Gravell

1
@MarcGravell cela nécessite-t-il que l'environnement d'exécution soit également 4,5 OU est-ce une fonctionnalité de compilateur?
kuldeep

5
C # est tellement bien conçu. Cela ne cesse de m'étonner. Merci Marc!
nmit026

75

Utilisez la méthode StackFrame.GetFileLineNumber , par exemple:

private static void ReportError(string message)
{
     StackFrame callStack = new StackFrame(1, true);
     MessageBox.Show("Error: " + message + ", File: " + callStack.GetFileName() 
          + ", Line: " + callStack.GetFileLineNumber());
}

Voir l'entrée du blog de Scott Hanselman pour plus d'informations.

[Modifier: a ajouté ce qui suit]

Pour ceux qui utilisent .Net 4.5 ou version ultérieure, considérez les attributs CallerFilePath , CallerMethodName et CallerLineNumber dans l'espace de noms System.Runtime.CompilerServices. Par exemple:

public void TraceMessage(string message,
        [CallerMemberName] string callingMethod = "",
        [CallerFilePath] string callingFilePath = "",
        [CallerLineNumber] int callingFileLineNumber = 0)
{
    // Write out message
}

Les arguments doivent être stringpour CallerMemberNameet CallerFilePathet un intpour CallerLineNumberet doivent avoir une valeur par défaut. La spécification de ces attributs sur les paramètres de méthode indique au compilateur d'insérer la valeur appropriée dans le code appelant au moment de la compilation, ce qui signifie qu'il fonctionne par obfuscation. Voir Informations sur l'appelant pour plus d'informations.


@MonsterMMORPG Cela fonctionne indépendamment du fait qu'il y ait une erreur ou non. La classe StackFrame regarde simplement la méthode appelant le courant en cours d'exécution. Le premier argument du constructeur StackFrame est la profondeur d'appel (1) et le deuxième argument indique que les informations de fichier sont nécessaires.
akton

3
Si vous compilez l' StackFrameexemple sur Mono , assurez-vous de l' utiliser--debug au moment de la compilation et au moment de l'exécution
bernard paulus

StackFramen'est pas disponible dans .NET Core. Utilisez la réponse de Marc Gravell.
Jesse Chisholm

L'utilisation de la valeur par défaut = string.Emptygénère l'erreur "La valeur du paramètre par défaut pour 'callingFilePath' doit être une constante de compilation" !
stomie

1
@stomy J'ai changé le fichier examp [pour utiliser des guillemets doubles ( "") au lieu de string.Empty.
akton

22

Je préfère une doublure donc:

int lineNumber = (new System.Diagnostics.StackFrame(0, true)).GetFileLineNumber();

8
il a besoin d'un fichier .pdb .. que nous ne générons / copions généralement pas sur le serveur de production.
Deepak Sharma

4

Pour ceux qui ont besoin d'une solution de méthode .NET 4.0+:

using System;
using System.IO;
using System.Diagnostics;

public static void Log(string message) {
   StackFrame stackFrame = new System.Diagnostics.StackTrace(1).GetFrame(1);
   string fileName = stackFrame.GetFileName();
   string methodName = stackFrame.GetMethod().ToString();
   int lineNumber = stackFrame.GetFileLineNumber();

   Console.WriteLine("{0}({1}:{2})\n{3}", methodName, Path.GetFileName(fileName), lineNumber, message);
}

Comment appeler:

void Test() {
   Log("Look here!");
}

Production:

Test d'annulation () (FILENAME.cs: 104)

Regardez ici!

Changez le format Console.WriteLine comme vous le souhaitez!


3
ne fonctionnera pas dans tous les cas .. il a toujours besoin d'un fichier .pdb, que nous ne générons / copions généralement pas sur le serveur de production. essayez avec l'attribut C # 5.0 Caller *.
Deepak Sharma

2
Si vous utilisez plutôt ceci: System.Diagnostics.Debug.WriteLine(String.Format("{0}({1}): {2}: {3}", fileName, lineNumber, methodName, message));vous pouvez cliquer sur la ligne dans la fenêtre de sortie et être redirigé vers cette ligne dans la source.
Jesse Chisholm

3

Si c'est dans un bloc try catch, utilisez ceci.

try
{
    //Do something
}
catch (Exception ex)
{
    System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
    Console.WriteLine("Line: " + trace.GetFrame(0).GetFileLineNumber());
}

1

Dans .NET 4.5, vous pouvez obtenir le numéro de ligne en créant la fonction:

static int LineNumber([System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0)
{
    return lineNumber; 
}

Ensuite, chaque fois que vous appelez, LineNumber()vous aurez la ligne actuelle. Cela présente l'avantage par rapport à toute solution utilisant StackTrace de fonctionner à la fois dans le débogage et la version.

Donc, en prenant la demande initiale de ce qui est requis, cela deviendrait:

MessageBox.Show("Error enter code here line number " + LineNumber());

Cela s'appuie sur l'excellente réponse de Marc Gravell.


Cela ne renvoie pas le bon numéro de ligne. Je dois soustraire 191 pour bien faire les choses pour une raison quelconque.
Daniel

Intéressant. Fonctionne bien ici pour moi. Les numéros de lien sont-ils activés dans l'EDI? Si vous appelez cette fonction à différents endroits dans le fichier, devez-vous encore soustraire 191? Ce sera soit un bogue du compilateur (peu probable, mais possible), soit un bloc réduit sur votre page (bien que cela ne devrait pas empêcher les numéros de ligne d'être corrects, cela pourrait expliquer la différence si vous comptiez plutôt que de rechercher le numéro de ligne). Si vous pouvez me contacter hors ligne, j'aimerais aller au fond des choses.
Brian Cryer le

Aucun bloc réduit, les numéros de ligne sont activés, doivent encore soustraire 191 quel que soit l'endroit d'où il est appelé. Je sais ... bizarre.
Daniel
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.