C # jika / kemudian arahan untuk debug vs rilis

434

Di properti Solusi, saya memiliki Konfigurasi yang diatur ke "rilis" untuk satu-satunya proyek saya.

Pada awal rutin utama, saya memiliki kode ini, dan itu menunjukkan "Mode = Debug". Saya juga memiliki dua baris ini di bagian paling atas:

#define DEBUG 
#define RELEASE

Apakah saya menguji variabel yang benar?

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

Tujuan saya adalah untuk menetapkan standar yang berbeda untuk variabel berdasarkan mode debug vs rilis.

NealWalters
sumber
13
Anda mendefinisikan KEDUA debug dan lepaskan.
Eric Dahlvang

Jawaban:

720

DEBUGSaya _DEBUGharus sudah didefinisikan dalam VS.

Hapus #define DEBUGkode Anda. Atur preprocessor dalam konfigurasi build untuk build spesifik itu.

Alasannya mencetak "Mode = Debug" adalah karena Anda #definedan kemudian melewatkan elif.

Cara yang benar untuk memeriksa adalah:

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

Jangan periksa RELEASE.

psikotik
sumber
78
Saya ingin menambahkan bahwa jika seseorang hanya ingin memeriksa RELEASE maka seseorang dapat melakukan ini:
3
Kenapa #ifdan tidak #ifdef?
Bob Stein
23
@ BobStein-VisiBone Ingat kita berbicara tentang C # di sini, bukan C. #ifdefkhusus untuk preprosesor C / C ++, C # mengamanatkan penggunaan #if.
jduncanator
27
@Jess, saya percaya ini adalah Visual Studio yang melakukan perubahan, bukan ReSharper
Dakotah Hicock
1
@DakotahHicock Benar, saya tidak menggunakan resharper dan VS mengeluarkannya.
makoshichi
295

Secara default, Visual Studio mendefinisikan DEBUG jika proyek dikompilasi dalam mode Debug dan tidak mendefinisikannya jika itu dalam mode rilis. RELEASE tidak didefinisikan dalam mode Rilis secara default. Gunakan sesuatu seperti ini:

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

Jika Anda ingin melakukan sesuatu hanya dalam mode rilis:

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

Juga, ada baiknya menunjukkan bahwa Anda dapat menggunakan [Conditional("DEBUG")]atribut pada metode yang mengembalikannya voidhanya dieksekusi jika simbol tertentu didefinisikan. Kompiler akan menghapus semua panggilan ke metode tersebut jika simbol tidak didefinisikan:

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

void Test() {
    PrintLog();
}
Mehrdad Afshari
sumber
6
Jawaban yang luar biasa, dihargai.
Duy Tran
211

Saya lebih suka memeriksanya seperti ini daripada mencari #definearahan:

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

Dengan peringatan itu tentu saja Anda bisa mengkompilasi dan menggunakan sesuatu dalam mode debug tetapi masih belum memiliki debugger terpasang.

Joel Coehoorn
sumber
1
Terima kasih! Saya bahkan belum tahu apa itu "#defines" jadi ini adalah solusi hebat!
Tim
Dan saya kasus saya, ini melakukan apa yang saya inginkan. Saya sebenarnya ingin tahu apakah saya memiliki debugger terpasang, karena saya tahu saya memiliki beberapa kode saya tidak ingin dieksekusi jika saya memiliki debugger terpasang. Ini luar biasa!
JFTxJ
1
Jika secara pribadi suka menggunakan #IF DEBUGdalam situasi kode debugging yang seharusnya tidak bertahan lama. Untuk kode produksi, saya setuju dengan penggunaan di atas.
Coops
10
Yang menarik untuk melakukan ini alih-alih menggunakan #DEBUGadalah bahwa pernyataan if ini ada dalam kode Anda dan selalu diperiksa ketika #DEBUGjawabannya menghapus kode yang tidak berlaku pada waktu kompilasi sehingga Anda tidak memiliki pemeriksaan run-time dan Anda. exe (atau apa pun yang Anda kompilasi) lebih kecil.
Dan
1
@ user34660. Jawaban untuk pertanyaan yang disebutkan adalah "tidak", yang tidak benar-benar membantu siapa pun.
Steve Smith
52

Saya bukan penggemar besar dari hal-hal #jika, terutama jika Anda menyebar di seluruh basis kode Anda karena akan memberi Anda masalah di mana Debug membangun pass tetapi rilis build gagal jika Anda tidak hati-hati.

Jadi inilah yang saya buat (terinspirasi oleh #ifdef di 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;
    }
}
Tod Thomson
sumber
2
Hei sekarang, itu cukup kreatif. Saya suka Anda menggunakan atribut untuk mengatur properti.
kenchilada
3
Ini memiliki keuntungan karena tidak terkena bug refactoring di Resharper yang dapat mengacaukan kode Anda berdasarkan pengaturan kondisional saat ini.
Jafin
3
Saya suka ini tetapi saya bertanya-tanya mengapa tidak membuat implementasi tunggal untuk ini, bukan layanan. Ini spesifik sistem dan berhenti Anda harus khawatir tentang menyuntikkannya di mana-mana. (dapatkah Anda membayangkan skenario di mana penerapan fungsi ini akan berbeda?
BastanteCaro
1
Saya sebenarnya memiliki layanan tunggal dan implementasi dalam satu kelas yang saya gunakan sekarang sehingga Anda dapat memiliki pilihan cara untuk menggunakannya ... Tentu saja implementasi layanan memiliki manfaat menjadi lebih mudah untuk "mematikan" begitu Anda dapat menguji kedua jalur kode ...
Tod Thomson
Saya bertanya-tanya mengapa DebuggingServicebukan kelas statis dan mengapa Anda memerlukan antarmuka? Apakah ini ada hubungannya dengan menggunakan ini dengan wadah IOC?
Ben
23
bool isDebug = false;
Debug.Assert(isDebug = true); // '=', not '=='

Metode ini Debug.Assertmemiliki atribut bersyarat DEBUG. Jika tidak didefinisikan, panggilan dan tugas isDebug = true yang dihilangkan :

Jika simbolnya ditentukan, panggilan sudah termasuk; jika tidak, panggilan (termasuk evaluasi parameter panggilan) dihilangkan.

Jika DEBUGdidefinisikan, isDebugdiatur ke true(dan diteruskan ke Debug.Assert, yang tidak melakukan apa pun dalam kasus itu).

AlexD
sumber
Ini juga solusi yang cukup kreatif. :)
Jack
Bagus. Untuk variabel iterasi yang perlu diubah antara Debug dan Rilis ... var iterations = 10; Debug.Assert((iterations = Int32.MaxValue) > 0);
Matt Davis
19

Jika Anda mencoba menggunakan variabel yang ditentukan untuk tipe build Anda harus menghapus dua baris ...

#define DEBUG  
#define RELEASE 

... ini akan menyebabkan #jika (DEBUG) selalu benar.

Juga tidak ada simbol kompilasi bersyarat standar untuk RELEASE . Jika Anda ingin mendefinisikan satu pergi ke properti proyek, klik pada tab Build dan kemudian tambahkan RELEASE ke kotak teks simbol kompilasi simbol bersyarat di bawah judul Umum .

Pilihan lain adalah melakukan ini ...

#if DEBUG
    Console.WriteLine("Debug");
#else
    Console.WriteLine("Release");
#endif
Matthew Whited
sumber
7

Hapus definisi Anda di atas

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

Versi sedikit dimodifikasi (bastardized?) Dari jawaban oleh Tod Thomson sebagai fungsi statis daripada kelas yang terpisah (saya ingin dapat menyebutnya dalam tampilan WebForm dari kelas viewutils yang sudah saya sertakan).

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

    WellAreWe(ref debugging);

    return debugging;
}

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

Pastikan untuk mendefinisikan konstanta DEBUG dalam Properti Membangun Proyek. Ini akan mengaktifkan #if DEBUG. Saya tidak melihat konstan RELEASE yang telah ditentukan sebelumnya, sehingga dapat menyiratkan bahwa apa pun yang Tidak ada dalam blok DEBUG adalah mode RELEASE.

Tetapkan konstanta DEBUG di Project Build Properties

gridtrak
sumber
5

NameSpace

using System.Resources;
using System.Diagnostics;

metode

   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;
    }
Ehsan Enaloo
sumber
3

Kiat yang mungkin menghemat banyak waktu - jangan lupa meskipun Anda memilihnya debug bawah konfigurasi build (pada menu vs2012 / 13 itu ada di bawah BUILD => CONFIGURATION MANAGER) - itu tidak cukup.

Anda perlu memperhatikan PUBLISH Configuration, karena:

masukkan deskripsi gambar di sini

ilans
sumber
0

Karena tujuan arahan COMPILER ini adalah untuk memberi tahu kompiler untuk TIDAK menyertakan kode, kode debug, kode beta, atau mungkin kode yang diperlukan oleh semua pengguna akhir Anda, kecuali katakanlah pada departemen periklanan, yaitu #Define AdDept yang ingin Anda dapat menyertakan atau menghapusnya berdasarkan kebutuhan Anda. Tanpa harus mengubah kode sumber Anda jika misalnya non AdDept bergabung ke dalam AdDept. Maka semua yang perlu dilakukan adalah memasukkan direktif #AdDept di halaman properti opsi kompiler dari versi program yang ada dan melakukan kompilasi dan wa la! kode program yang digabungkan muncul secara hidup !.

Anda mungkin juga ingin menggunakan deklaratif untuk proses baru yang tidak siap untuk prime time atau yang tidak dapat aktif dalam kode sampai saatnya untuk melepaskannya.

Bagaimanapun, itulah cara saya melakukannya.

mrMagik3805
sumber
0

Saya harus memikirkan cara yang lebih baik. Saya sadar bahwa #jika blok adalah komentar yang efektif dalam konfigurasi lain (dengan asumsi DEBUGatau RELEASE; tetapi benar dengan simbol apa pun)

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");
        }
Hasitha Jayawardana
sumber
0

Hapus definisi dan periksa apakah kondisinya pada mode debug. Anda tidak perlu memeriksa apakah arahan dalam mode rilis.

Sesuatu seperti ini:

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