Mana yang lebih baik untuk digunakan, dan mengapa, pada proyek besar:
#if DEBUG
public void SetPrivateValue(int value)
{ ... }
#endif
atau
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
Mana yang lebih baik untuk digunakan, dan mengapa, pada proyek besar:
#if DEBUG
public void SetPrivateValue(int value)
{ ... }
#endif
atau
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
Jawaban:
Ini benar-benar tergantung pada apa yang Anda tuju:
#if DEBUG
: Kode di sini bahkan tidak akan mencapai IL pada rilis.[Conditional("DEBUG")]
: Kode ini akan mencapai IL, namun panggilan ke metode ini akan dihilangkan kecuali DEBUG diatur saat pemanggil dikompilasi.Secara pribadi saya menggunakan keduanya tergantung pada situasi:
Contoh Bersyarat ("DEBUG"): Saya menggunakan ini sehingga saya tidak harus kembali dan mengedit kode saya nanti selama rilis, tetapi selama debugging saya ingin memastikan saya tidak membuat kesalahan ketik. Fungsi ini memeriksa apakah saya mengetikkan nama properti dengan benar ketika mencoba menggunakannya dalam hal-hal INotifyPropertyChanged saya.
[Conditional("DEBUG")]
[DebuggerStepThrough]
protected void VerifyPropertyName(String propertyName)
{
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
Debug.Fail(String.Format("Invalid property name. Type: {0}, Name: {1}",
GetType(), propertyName));
}
Anda benar-benar tidak ingin membuat fungsi menggunakan #if DEBUG
kecuali Anda bersedia untuk membungkus setiap panggilan ke fungsi itu dengan yang sama #if DEBUG
:
#if DEBUG
public void DoSomething() { }
#endif
public void Foo()
{
#if DEBUG
DoSomething(); //This works, but looks FUGLY
#endif
}
melawan:
[Conditional("DEBUG")]
public void DoSomething() { }
public void Foo()
{
DoSomething(); //Code compiles and is cleaner, DoSomething always
//exists, however this is only called during DEBUG.
}
#Jika DEBUG contoh: Saya menggunakan ini ketika mencoba mengatur binding yang berbeda untuk komunikasi WCF.
#if DEBUG
public const String ENDPOINT = "Localhost";
#else
public const String ENDPOINT = "BasicHttpBinding";
#endif
Dalam contoh pertama, semua kode ada, tetapi hanya diabaikan kecuali DEBUG aktif. Dalam contoh kedua, const ENDPOINT diatur ke "Localhost" atau "BasicHttpBinding" tergantung pada apakah DEBUG diatur atau tidak.
Pembaruan: Saya memperbarui jawaban ini untuk memperjelas poin penting dan rumit. Jika Anda memilih untuk menggunakan ConditionalAttribute
, ingatlah bahwa panggilan dihilangkan selama kompilasi, dan bukan runtime . Itu adalah:
MyLibrary.dll
[Conditional("DEBUG")]
public void A()
{
Console.WriteLine("A");
B();
}
[Conditional("DEBUG")]
public void B()
{
Console.WriteLine("B");
}
Ketika perpustakaan dikompilasi dengan mode rilis (yaitu tidak ada simbol DEBUG), itu akan selamanya memiliki panggilan B()
dari dalam A()
dihilangkan, bahkan jika panggilan ke A()
dimasukkan karena DEBUG didefinisikan dalam majelis panggilan.
Yah, perlu dicatat bahwa itu tidak berarti sama sekali.
Jika simbol DEBUG tidak didefinisikan, maka dalam kasus pertama SetPrivateValue
itu sendiri tidak akan dipanggil ... sedangkan dalam kasus kedua itu akan ada, tetapi setiap penelepon yang dikompilasi tanpa simbol DEBUG akan membuat panggilan tersebut dihilangkan.
Jika kode dan semua peneleponnya berada dalam rakitan yang sama perbedaan ini kurang penting - tetapi itu berarti bahwa dalam kasus pertama Anda juga perlu memiliki #if DEBUG
sekitar kode panggilan juga.
Secara pribadi saya akan merekomendasikan pendekatan kedua - tetapi Anda harus menjaga perbedaan di antara mereka jelas di kepala Anda.
Saya yakin banyak yang akan tidak setuju dengan saya, tetapi setelah menghabiskan waktu sebagai tukang bangunan terus-menerus mendengar "Tapi itu bekerja pada mesin saya!", Saya mengambil pendirian bahwa Anda sebaiknya tidak pernah menggunakan keduanya. Jika Anda benar-benar membutuhkan sesuatu untuk pengujian dan debugging, cari cara untuk membuat testabilitas itu terpisah dari kode produksi yang sebenarnya.
Abstraksi skenario dengan mengejek dalam unit test, buat satu versi dari hal-hal untuk satu skenario yang ingin Anda uji, tetapi jangan masukkan tes untuk debug ke dalam kode untuk binari yang Anda uji dan tulis untuk rilis produksi. Tes debug ini hanya menyembunyikan kemungkinan bug dari devs sehingga tidak ditemukan hingga nanti dalam proses.
#if debug
atau konstruksi serupa dalam kode Anda?
#if DEBUG
sehingga kita tidak secara tidak sengaja melakukan spam kepada orang lain saat menguji sistem yang harus mengirimkan email sebagai bagian dari proses. Kadang-kadang ini adalah alat yang tepat untuk pekerjaan itu :)
Yang ini bisa bermanfaat juga:
if (Debugger.IsAttached)
{
...
}
Debugger.IsAttached
harus dipanggil pada saat runtime bahkan dalam rilis rilis.
Dengan contoh pertama, SetPrivateValue
tidak akan ada di build jika DEBUG
tidak ditentukan, dengan contoh kedua, panggilan ke SetPrivateValue
tidak akan ada di build jika DEBUG
tidak ditentukan.
Dengan contoh pertama, Anda juga harus membungkus semua panggilan SetPrivateValue
dengan #if DEBUG
.
Dengan contoh kedua, panggilan ke SetPrivateValue
akan dihilangkan, tetapi perlu diketahui bahwa SetPrivateValue
itu sendiri masih akan dikompilasi. Ini berguna jika Anda sedang membangun perpustakaan, jadi aplikasi yang mereferensikan perpustakaan Anda masih dapat menggunakan fungsi Anda (jika kondisinya terpenuhi).
Jika Anda ingin menghilangkan panggilan dan menghemat ruang callee, Anda bisa menggunakan kombinasi kedua teknik ini:
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
#if DEBUG
// method body here
#endif
}
#if DEBUG
sekitarConditional("DEBUG")
tidak menghapus panggilan ke fungsi itu, itu hanya menghapus fungsi dari IL alltogether, jadi Anda masih memiliki panggilan ke fungsi yang tidak ada (kesalahan kompilasi).
Mari kita anggap kode Anda juga memiliki #else
pernyataan yang mendefinisikan fungsi rintisan nol, membahas salah satu poin Jon Skeet. Ada perbedaan penting kedua di antara keduanya.
Misalkan fungsi #if DEBUG
atau Conditional
ada dalam DLL yang dirujuk oleh proyek utama Anda yang dapat dieksekusi. Dengan menggunakan #if
, evaluasi kondisional akan dilakukan sehubungan dengan pengaturan kompilasi perpustakaan. Menggunakan Conditional
atribut, evaluasi kondisi akan dilakukan sehubungan dengan pengaturan kompilasi dari penyerang.
Saya memiliki ekstensi SOAP WebService untuk mencatat lalu lintas jaringan menggunakan kustom [TraceExtension]
. Saya menggunakan ini hanya untuk membangun Debug dan menghilangkan dari rilis membangun. Gunakan #if DEBUG
untuk membungkus [TraceExtension]
atribut sehingga menghapusnya dari rilis Rilis .
#if DEBUG
[TraceExtension]
#endif
[System.Web.Service.Protocols.SoapDocumentMethodAttribute( ... )]
[ more attributes ...]
public DatabaseResponse[] GetDatabaseResponse( ...)
{
object[] results = this.Invoke("GetDatabaseResponse",new object[] {
... parmeters}};
}
#if DEBUG
[TraceExtension]
#endif
public System.IAsyncResult BeginGetDatabaseResponse(...)
#if DEBUG
[TraceExtension]
#endif
public DatabaseResponse[] EndGetDatabaseResponse(...)
Biasanya Anda akan membutuhkannya di Program.cs di mana Anda ingin memutuskan untuk menjalankan Debug pada kode Non-Debug dan itu terlalu banyak di Windows Services. Jadi saya membuat isdebugMode bidang readonly dan mengatur nilainya dalam konstruktor statis seperti yang ditunjukkan di bawah ini.
static class Program
{
#region Private variable
static readonly bool IsDebugMode = false;
#endregion Private variable
#region Constrcutors
static Program()
{
#if DEBUG
IsDebugMode = true;
#endif
}
#endregion
#region Main
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
if (IsDebugMode)
{
MyService myService = new MyService(args);
myService.OnDebug();
}
else
{
ServiceBase[] services = new ServiceBase[] { new MyService (args) };
services.Run(args);
}
}
#endregion Main
}