Kod „Tylko debuguj”, który powinien działać tylko wtedy, gdy jest „włączony”

94

Chciałbym dodać kod C # „tylko do debugowania”, który działa tylko wtedy, gdy osoba debugująca tego zażąda. W C ++ robiłem coś podobnego do następującego:

void foo()
{   
  // ...
  #ifdef DEBUG
  static bool s_bDoDebugOnlyCode = false;
  if (s_bDoDebugOnlyCode)
  {
      // Debug only code here gets executed when the person debugging 
      // manually sets the bool above to true.  It then stays for the rest
      // of the session until they set it to false.
  }
  #endif
 // ...
}

Nie mogę zrobić dokładnie tego samego w C #, ponieważ nie ma lokalnych statystyk.

Pytanie : Jaki jest najlepszy sposób osiągnięcia tego w C #?

  1. Czy należy używać pola statycznego klasy prywatnej z dyrektywami preprocesora języka C # ( #if/#endif DEBUG)?
  2. Czy powinienem użyć atrybutu warunkowego (do przechowywania kodu), a następnie pola statycznego klasy prywatnej ( nie otoczonego dyrektywami preprocesora C # #if/#endif DEBUG?).
  3. Coś innego?
Matt Smith
źródło

Odpowiedzi:

146

Zmienna instancji prawdopodobnie byłaby sposobem na zrobienie tego, co chcesz. Możesz uczynić go statycznym, aby utrzymywał tę samą wartość przez cały czas życia programu (lub wątku, w zależności od modelu pamięci statycznej), lub uczynić go zwykłą instancją zmienną, aby kontrolować ją przez czas życia instancji obiektu. Jeśli ta instancja jest singletonem, będą zachowywać się w ten sam sposób.

#if DEBUG
private /*static*/ bool s_bDoDebugOnlyCode = false;
#endif

void foo()
{   
  // ...
#if DEBUG
  if (s_bDoDebugOnlyCode)
  {
      // Code here gets executed only when compiled with the DEBUG constant, 
      // and when the person debugging manually sets the bool above to true.  
      // It then stays for the rest of the session until they set it to false.
  }
#endif
 // ...
}

Aby być kompletnym, pragmy (dyrektywy preprocesora) są uważane za trochę niezdarne do kontrolowania przepływu programu. NET ma wbudowaną odpowiedź na połowę tego problemu, używając atrybutu „Warunkowy”.

private /*static*/ bool doDebugOnlyCode = false; 
[Conditional("DEBUG")]
void foo()
{   
  // ...    
  if (doDebugOnlyCode)
  {
      // Code here gets executed only when compiled with the DEBUG constant, 
      // and when the person debugging manually sets the bool above to true.  
      // It then stays for the rest of the session until they set it to false.
  }    
  // ...
}

Żadnych pragm, dużo czystszych. Wadą jest to, że warunkowe można zastosować tylko do metod, więc będziesz musiał poradzić sobie ze zmienną logiczną, która nie robi nic w kompilacji wydania. Ponieważ zmienna istnieje wyłącznie w celu przełączenia z hosta wykonawczego VS, aw kompilacji wydania jej wartość nie ma znaczenia, jest całkiem nieszkodliwa.

KeithS
źródło
2
Wreszcie - ktoś, kto przeczytał całe pytanie. Dzięki, okej - wydawało się, że to trochę przydługie rozwiązanie (konieczność posiadania dwóch sekcji preprocesora), ale być może jest to najlepsze, co C # może zrobić dla tego, co chcę.
Matt Smith,
6
meh. Nie nazwałbym tego zbyt długim tylko dlatego, że dodajesz jeszcze dwie linie dyrektywy preprocesora.
KeithS
4
Cóż, bardzo dziękuję Patricku za odrzucenie zaakceptowanej odpowiedzi 3-latka na taką, która nie rozwiązuje całego problemu. Atrybut warunkowy zapobiega tylko wykonywaniu metody w trybach innych niż debugowanie. OP chciał nie tylko tego, ale także móc „włączyć” kod za pomocą debuggera. Znacznik gokkora, który został użyty, nie zostanie skompilowany.
KeithS
2
Zauważ, że preprocesor mówi ci, czy program kompiluje się w trybie debugowania, ale nie czy debugger faktycznie działa.
Shane
65

To, czego szukasz, to

[ConditionalAttribute("DEBUG")]

atrybut.

Jeśli na przykład napiszesz metodę taką jak:

[ConditionalAttribute("DEBUG")]
public static void MyLovelyDebugInfoMethod(string message)
{
    Console.WriteLine("This message was brought to you by your debugger : ");
    Console.WriteLine(message);
}

każde wywołanie tej metody wewnątrz własnego kodu zostanie wykonane tylko w trybie debugowania. Jeśli budujesz swój projekt w trybie wydania, nawet wywołanie metody „MyLovelyDebugInfoMethod” zostanie zignorowane i usunięte z pliku binarnego.

Aha i jeszcze jedno, jeśli próbujesz określić, czy Twój kod jest obecnie debugowany w momencie wykonywania, możesz również sprawdzić, czy bieżący proces jest podpięty przez JIT. Ale to wszystko razem jest innym przypadkiem. Napisz komentarz, jeśli właśnie tego próbujesz.

gokkor
źródło
3
Korzystając z Attribute, nie musisz pisać sufiksu „Attribute”. Conditional = ConditionalAttribute. Klasa atrybutu powinna kończyć się wyrażeniem „Atrybut”, ale można ją pominąć, gdy jest używana jako atrybut w kodzie. Łatwiej jest odczytać, gdy przyrostek zostanie pominięty.
Eric Ouellet
23

Możesz spróbować tego, jeśli potrzebujesz kodu do uruchomienia tylko wtedy, gdy masz dołączony debugger do procesu.

if (Debugger.IsAttached)
{
     // do some stuff here
}
Wes
źródło
Dziękuję Ci! Dokładnie tego chciałem: wykonaj Console.ReadLine () na końcu, aby zapobiec zamknięciu okna konsoli podczas debugowania.
VVS,
4

Myślę, że warto wspomnieć, że [ConditionalAttribute]znajduje się w System.Diagnostics;przestrzeni nazw. Trochę się potknąłem, gdy dostałem:

Error 2 The type or namespace name 'ConditionalAttribute' could not be found (are you missing a using directive or an assembly reference?)

po pierwszym użyciu (myślałem, że będzie System).

XyberICE
źródło
3

Jeśli chcesz wiedzieć, czy debugowanie, wszędzie w programie. Użyj tego.

Zadeklaruj zmienną globalną.

bool isDebug=false;

Utwórz funkcję do sprawdzania trybu debugowania

[ConditionalAttribute("DEBUG")]
    public static void isDebugging()
    {
        isDebug = true;
    }

W metodzie initialize wywołaj funkcję

isDebugging();

Teraz w całym programie. Możesz sprawdzić debugowanie i wykonać operacje. Mam nadzieję że to pomoże!

Mohamed Alikhan
źródło
1
AFAIK: to i jego warianty to jedyny pewny sposób, aby dowiedzieć się, czy program myje skompilowany z ustawioną flagą debugowania.
LosManos