C # jeśli / to dyrektywy debugowania vs wydania


432

We właściwościach rozwiązania mam konfigurację ustawioną na „release” dla mojego jedynego projektu.

Na początku głównej procedury mam ten kod i pokazuje on „Mode = Debug”. Te dwie linie mam też na samej górze:

#define DEBUG 
#define RELEASE

Czy testuję odpowiednią zmienną?

#if (DEBUG)
            Console.WriteLine("Mode=Debug"); 
#elif (RELEASE)
            Console.WriteLine("Mode=Release"); 
#endif

Moim celem jest ustawienie różnych wartości domyślnych dla zmiennych opartych na trybie debugowania vs.


13
Definiujesz ZARÓWNO debugowanie i wydanie.
Eric Dahlvang,

Odpowiedzi:


718

DEBUG/ _DEBUGnależy już zdefiniować w VS.

Usuń #define DEBUGw swoim kodzie. Ustaw preprocesory w konfiguracji kompilacji dla tej konkretnej kompilacji.

Powodem, dla którego drukuje „Tryb = Debugowanie”, jest twój, #definea następnie pomija elif.

Właściwy sposób sprawdzenia to:

#if DEBUG
    Console.WriteLine("Mode=Debug"); 
#else
    Console.WriteLine("Mode=Release"); 
#endif

Nie sprawdzaj RELEASE.


77
Chciałem dodać, że jeśli ktoś chciałby tylko sprawdzić, czy można

3
Dlaczego #ifnie #ifdef?
Bob Stein

23
@ BobStein-VisiBone Pamiętaj, że mówimy tutaj o C #, nie C. #ifdefjest specyficzny dla preprocesora C / C ++, C # wymaga użycia #if.
jduncanator

27
@Jess, wydaje mi się, że to Visual Studio robi siwienie, a nie ReSharper
Dakotah Hicock

1
@DakotahHicock Zgadza się, nie używam resharpera i VS grays.
makoshichi

294

Domyślnie Visual Studio definiuje DEBUGĘ, jeśli projekt jest kompilowany w trybie debugowania i nie definiuje go, jeśli jest w trybie zwolnienia. RELEASE nie jest domyślnie zdefiniowane w trybie Release. Użyj czegoś takiego:

#if DEBUG
  // debug stuff goes here
#else
  // release stuff goes here
#endif

Jeśli chcesz zrobić coś tylko w trybie zwolnienia:

#if !DEBUG
  // release...
#endif

Warto również zauważyć, że można użyć [Conditional("DEBUG")]atrybutu w metodach, które powracają, voidaby były wykonywane tylko wtedy, gdy określony jest określony symbol. Kompilator usunie wszystkie wywołania tych metod, jeśli symbol nie zostanie zdefiniowany:

[Conditional("DEBUG")]
void PrintLog() {
    Console.WriteLine("Debug info");
}

void Test() {
    PrintLog();
}

6
Doceniona świetna odpowiedź.
Duy Tran

210

Wolę to sprawdzić w ten sposób niż szukać #definedyrektyw:

if (System.Diagnostics.Debugger.IsAttached)
{
   //...
}
else
{
   //...
}

Z zastrzeżeniem, że można oczywiście skompilować i wdrożyć coś w trybie debugowania, ale nadal nie ma podłączonego debugera.


1
Dziękuję Ci! Nie wiem nawet, czym są „#defines”, więc jest to świetne rozwiązanie!
Tim

I w moim przypadku robi to dokładnie to, czego chcę. Naprawdę chcę wiedzieć, czy mam podłączony debugger, ponieważ wiem, że mam jakiś kod, którego nie chcę wykonywać, jeśli mam podłączony debugger. To jest niesamowite!
JFTxJ,

1
Jeśli osobiście lubisz używać #IF DEBUGw sytuacji debugowania kodu, który nie powinien trwać. W przypadku kodu produkcyjnego zgadzam się na użycie powyższego.
Coops,

10
Wadą tego działania zamiast używania #DEBUGjest to, że ta instrukcja if znajduje się w kodzie i zawsze jest sprawdzana, ponieważ #DEBUGodpowiedź usuwa kod, który nie ma zastosowania w czasie kompilacji, więc nie masz kontroli wykonania w czasie wykonywania. exe (lub cokolwiek skompilujesz) jest mniejszy.
Dan

1
@ user34660. Odpowiedź na zadane pytanie brzmi „nie”, co tak naprawdę nikomu nie pomaga.
Steve Smith

51

Nie jestem wielkim fanem rzeczy #if, szczególnie jeśli rozprowadzasz je wokół swojej bazy kodu, ponieważ spowoduje to problemy z przejściem kompilacji Debug, ale kompilacje Release zakończą się niepowodzeniem, jeśli nie będziesz ostrożny.

Oto co wymyśliłem (zainspirowany #ifdef w C # ):

public interface IDebuggingService
{
    bool RunningInDebugMode();
}

public class DebuggingService : IDebuggingService
{
    private bool debugging;

    public bool RunningInDebugMode()
    {
        //#if DEBUG
        //return true;
        //#else
        //return false;
        //#endif
        WellAreWe();
        return debugging;
    }

    [Conditional("DEBUG")]
    private void WellAreWe()
    {
        debugging = true;
    }
}

2
Hej, to całkiem kreatywne. Podoba mi się użycie atrybutu do ustawienia właściwości.
kenchilada

3
Ma to tę zaletę, że nie zostaje trafione przez refaktoryzację błędów w Resharper, które mogą zepsuć kod w oparciu o bieżącą konfigurację warunkową.
Jafin,

3
Podoba mi się to, ale zastanawiam się, dlaczego nie utworzyć dla tego singletonu zamiast usługi. Jest to specyficzne dla systemu i nie musisz się martwić, że wstrzykniesz go wszędzie. (czy możesz sobie wyobrazić scenariusz, w którym wdrożenie tej funkcjonalności byłoby inne?
BastanteCaro,

1
Tak naprawdę mam singleton i implementację usługi w jednej klasie, z której teraz korzystam, więc możesz wybrać, w jaki sposób z niej skorzystać ... Oczywiście implementacja usługi ma tę zaletę, że łatwiej ją „usunąć”, więc że możesz przetestować obie ścieżki kodu ...
Tod Thomson

Zastanawiam się, dlaczego DebuggingServicenie jest to klasa statyczna i dlaczego potrzebujesz interfejsu? Czy to ma coś wspólnego z używaniem tego z kontenerem IoC?
Ben

23
bool isDebug = false;
Debug.Assert(isDebug = true); // '=', not '=='

Metoda Debug.Assertma atrybut warunkowy DEBUG. Jeśli nie jest zdefiniowane, połączenie i przypisanie isDebug = trueeliminowane :

Jeśli symbol jest zdefiniowany, połączenie jest uwzględniane; w przeciwnym razie połączenie (w tym ocena parametrów połączenia) zostanie pominięte.

Jeśli DEBUGjest zdefiniowane, isDebugjest ustawione na true(i przekazywane do Debug.Assert, co w tym przypadku nic nie robi).


To również dość kreatywne rozwiązanie. :)
Jack

Miły. Dla zmiennej iteracyjnej, która musi się zmieniać między debugowaniem a wydaniem ... var iterations = 10; Debug.Assert((iterations = Int32.MaxValue) > 0);
Matt Davis,

19

Jeśli próbujesz użyć zmiennej zdefiniowanej dla typu kompilacji, powinieneś usunąć dwie linie ...

#define DEBUG  
#define RELEASE 

... spowoduje to #if (DEBUG) będzie zawsze prawdziwe.

Nie ma też domyślnego symbolu kompilacji warunkowej dla WYDANIA . Jeśli chcesz zdefiniować jedno przejście do właściwości projektu, kliknij kartę Kompiluj , a następnie dodaj UWOLNIENIE do pola tekstowego Symbole kompilacji warunkowej pod nagłówkiem Ogólne .

Inną opcją byłoby zrobienie tego ...

#if DEBUG
    Console.WriteLine("Debug");
#else
    Console.WriteLine("Release");
#endif

7

Usuń definicje u góry

#if DEBUG
        Console.WriteLine("Mode=Debug"); 
#else
        Console.WriteLine("Mode=Release"); 
#endif

7

Nieznacznie zmodyfikowana (zaryzykowana?) Wersja odpowiedzi Toda Thomsona jako funkcja statyczna, a nie osobna klasa (chciałem móc ją wywoływać w powiązaniu widoku WebForm z klasy viewutils, którą już załączyłem).

public static bool isDebugging() {
    bool debugging = false;

    WellAreWe(ref debugging);

    return debugging;
}

[Conditional("DEBUG")]
private static void WellAreWe(ref bool debugging)
{
    debugging = true;
}

6

Należy zdefiniować stałą DEBUG we właściwościach kompilacji projektu. Umożliwi to #if DEBUG. Nie widzę wstępnie zdefiniowanej stałej RELEASE, więc może to sugerować, że wszystko, co nie jest w bloku DEBUG, jest trybem RELEASE.

Zdefiniuj stałą DEBUG we Właściwościach kompilacji projektu


5

NameSpace

using System.Resources;
using System.Diagnostics;

metoda

   private static bool IsDebug()
    {
        object[] customAttributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(DebuggableAttribute), false);
        if ((customAttributes != null) && (customAttributes.Length == 1))
        {
            DebuggableAttribute attribute = customAttributes[0] as DebuggableAttribute;
            return (attribute.IsJITOptimizerDisabled && attribute.IsJITTrackingEnabled);
        }
        return false;
    }

3

Wskazówka, która może zaoszczędzić dużo czasu - nie zapomnij o tym, nawet jeśli wybierzesz debug w konfiguracji kompilacji (w menu vs2012 / 13 jest to w BUILD => MENEDŻER KONFIGURACJI) - to nie wystarczy.

Musisz zwrócić uwagę na PUBLIKAC Configurationjako taki:

wprowadź opis zdjęcia tutaj


0

Ponieważ celem tych dyrektyw KOMPILERA jest poinformowanie kompilatora, aby NIE zawierał kodu, kodu debugowania, kodu beta, a może kodu, który jest potrzebny wszystkim użytkownikom końcowym, z wyjątkiem tych, którzy mówią działowi reklamy, tj. #Define AdDept, który chcesz być w stanie je uwzględnić lub usunąć w zależności od potrzeb. Bez konieczności zmiany kodu źródłowego, jeśli na przykład nie-AdDept łączy się z AdDept. Następnie wszystko, co należy zrobić, to dołączyć dyrektywę #AdDept do strony właściwości opcji kompilatora istniejącej wersji programu i wykonać kompilację i wa la! kod scalonego programu odżywa!

Możesz także użyć deklaratywnego dla nowego procesu, który nie jest gotowy na czas pierwszorzędny lub który nie może być aktywny w kodzie, dopóki nie nadejdzie czas na jego zwolnienie.

W każdym razie tak to robię.


0

Zacząłem myśleć o lepszym sposobie. Przyszło mi do głowy, że bloki #if są skutecznie komentarzami w innych konfiguracjach (przy założeniu DEBUGlub RELEASE; ale prawdziwe z dowolnym symbolem)

public class Mytest
    {
        public DateTime DateAndTimeOfTransaction;
    }

    public void ProcessCommand(Mytest Command)
        {
            CheckMyCommandPreconditions(Command);
            // do more stuff with Command...
        }

        [Conditional("DEBUG")]
        private static void CheckMyCommandPreconditions(Mytest Command)
        {
            if (Command.DateAndTimeOfTransaction > DateTime.Now)
                throw new InvalidOperationException("DateTime expected to be in the past");
        }

0

Usuń definicje i sprawdź, czy warunek jest w trybie debugowania. Nie musisz sprawdzać, czy dyrektywa jest w trybie zwolnienia.

Coś takiego:

#if DEBUG
     Console.WriteLine("Mode=Debug"); 
#else
    Console.WriteLine("Mode=Release"); 
#endif
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.