สิ่งที่ดีกว่าใช้และทำไมในโครงการขนาดใหญ่:
#if DEBUG
public void SetPrivateValue(int value)
{ ... }
#endif
หรือ
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
สิ่งที่ดีกว่าใช้และทำไมในโครงการขนาดใหญ่:
#if DEBUG
public void SetPrivateValue(int value)
{ ... }
#endif
หรือ
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value)
{ ... }
คำตอบ:
มันขึ้นอยู่กับว่าคุณกำลังทำอะไร:
#if DEBUG
: รหัสในที่นี่จะไม่ถึง IL ที่วางจำหน่าย[Conditional("DEBUG")]
: รหัสนี้จะไปถึง IL อย่างไรก็ตามการโทรไปยังวิธีการจะถูกละเว้นยกเว้น DEBUG จะถูกตั้งค่าเมื่อมีการคอมไพล์ผู้โทรส่วนตัวฉันใช้ทั้งสองขึ้นอยู่กับสถานการณ์:
ตัวอย่างแบบมีเงื่อนไข ("DEBUG"):ฉันใช้สิ่งนี้เพื่อที่ฉันจะได้ไม่ต้องกลับไปแก้ไขรหัสในภายหลังในระหว่างการวางจำหน่าย แต่ในระหว่างการดีบักฉันต้องการให้แน่ใจว่าฉันไม่ได้พิมพ์ผิด ฟังก์ชันนี้ตรวจสอบว่าฉันพิมพ์ชื่อคุณสมบัติอย่างถูกต้องเมื่อพยายามใช้ในสิ่งที่ INotifyPropertyChanged ของฉัน
[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));
}
คุณไม่ต้องการสร้างฟังก์ชั่นที่ใช้#if DEBUG
เว้นแต่คุณจะยินดีที่จะตัดการเรียกทุกครั้งไปยังฟังก์ชันนั้นด้วยสิ่งเดียวกัน#if DEBUG
:
#if DEBUG
public void DoSomething() { }
#endif
public void Foo()
{
#if DEBUG
DoSomething(); //This works, but looks FUGLY
#endif
}
เมื่อเทียบกับ:
[Conditional("DEBUG")]
public void DoSomething() { }
public void Foo()
{
DoSomething(); //Code compiles and is cleaner, DoSomething always
//exists, however this is only called during DEBUG.
}
#if ตัวอย่าง DEBUG:ฉันใช้สิ่งนี้เมื่อพยายามตั้งค่าการเชื่อมต่าง ๆ สำหรับการสื่อสาร WCF
#if DEBUG
public const String ENDPOINT = "Localhost";
#else
public const String ENDPOINT = "BasicHttpBinding";
#endif
ในตัวอย่างแรกรหัสทั้งหมดมีอยู่ แต่จะถูกละเว้นยกเว้นว่า DEBUG เปิดอยู่ ในตัวอย่างที่สอง const ENDPOINT ถูกตั้งค่าเป็น "Localhost" หรือ "BasicHttpBinding" ขึ้นอยู่กับว่า DEBUG ถูกตั้งค่าหรือไม่
อัปเดต: ฉันกำลังอัปเดตคำตอบนี้เพื่อชี้แจงจุดที่สำคัญและยุ่งยาก หากคุณเลือกที่จะใช้ConditionalAttribute
โปรดจำไว้ว่าการโทรถูกละเว้นระหว่างการคอมไพล์ไม่ใช่การใช้งานจริง นั่นคือ:
MyLibrary.dll
[Conditional("DEBUG")]
public void A()
{
Console.WriteLine("A");
B();
}
[Conditional("DEBUG")]
public void B()
{
Console.WriteLine("B");
}
เมื่อไลบรารีถูกคอมไพล์กับโหมดการปล่อย (นั่นคือไม่มีสัญลักษณ์ DEBUG) มันจะมีการเรียกB()
จากภายในตลอดไปA()
แม้ว่าจะมีการเรียกไปยังA()
เนื่องจาก DEBUG ถูกกำหนดไว้ในแอสเซมบลีการโทร
มันก็น่าสังเกตว่าพวกเขาไม่ได้หมายถึงสิ่งเดียวกัน
หากสัญลักษณ์ DEBUG ไม่ได้ถูกกำหนดไว้ในกรณีแรกSetPrivateValue
ตัวเองจะไม่ถูกเรียก ... ในกรณีที่สองมันจะมีอยู่ แต่ผู้โทรใด ๆที่ถูกคอมไพล์โดยไม่มีสัญลักษณ์ DEBUG จะถูกตัดการโทรเหล่านั้น
ถ้ารหัสและทุกสายที่มีในตัวเดียวกันการชุมนุมแตกต่างนี้เป็นน้อยที่สำคัญ - แต่มันหมายความว่าในกรณีแรกที่คุณยังจะต้องมี#if DEBUG
รอบการเรียกรหัสเป็นอย่างดี
โดยส่วนตัวผมขอแนะนำวิธีที่สอง - แต่คุณต้องรักษาความแตกต่างระหว่างพวกเขาในหัวของคุณ
ฉันแน่ใจว่ามากมายจะไม่เห็นด้วยกับฉัน แต่มีการใช้เวลาเป็นคนสร้างได้ยินตลอดเวลา "แต่มันทำงานบนเครื่องของฉัน!" ฉันใช้จุดยืนที่คุณไม่ควรใช้อย่างใดอย่างหนึ่ง หากคุณต้องการบางสิ่งบางอย่างสำหรับการทดสอบและการดีบักหาวิธีทำให้การทดสอบนั้นแยกจากรหัสการผลิตจริง
สรุปสถานการณ์ที่มีการจำลองในการทดสอบหน่วยให้ทำสิ่งหนึ่งอย่างสำหรับสถานการณ์ที่คุณต้องการทดสอบ แต่ไม่ได้ทำการทดสอบเพื่อดีบักลงในรหัสสำหรับไบนารีที่คุณทดสอบและเขียนเพื่อการผลิต การทดสอบการแก้ไขข้อบกพร่องเหล่านี้เพียงซ่อนข้อบกพร่องที่เป็นไปได้จาก devs ดังนั้นพวกเขาจะไม่พบจนกระทั่งในภายหลังกระบวนการ
#if debug
หรือโครงสร้างที่คล้ายกันในรหัสของคุณ?
#if DEBUG
เพื่อไม่ให้ผู้อื่นสแปมโดยไม่ตั้งใจขณะทดสอบระบบที่ต้องส่งอีเมลเป็นส่วนหนึ่งของกระบวนการ บางครั้งเหล่านี้เป็นเครื่องมือที่เหมาะสมสำหรับงาน :)
อันนี้มีประโยชน์เช่นกัน:
if (Debugger.IsAttached)
{
...
}
Debugger.IsAttached
จะต้องถูกเรียกใช้ที่รันไทม์แม้ในรีลีส builds
ด้วยตัวอย่างแรกSetPrivateValue
จะไม่มีอยู่ในบิลด์หากDEBUG
ไม่ได้กำหนดไว้พร้อมกับตัวอย่างที่สองการเรียกร้องให้SetPrivateValue
ไม่มีอยู่ในบิลด์หากDEBUG
ไม่ได้กำหนดไว้
ด้วยตัวอย่างแรกคุณจะต้องตัดสายSetPrivateValue
ด้วย#if DEBUG
เช่นกัน
ด้วยตัวอย่างที่สองการโทรที่SetPrivateValue
จะถูกตัดออกไป แต่ต้องระวังว่าSetPrivateValue
ตัวเองจะยังคงถูกคอมไพล์ สิ่งนี้มีประโยชน์หากคุณกำลังสร้างห้องสมุดดังนั้นแอปพลิเคชันที่อ้างอิงห้องสมุดของคุณยังสามารถใช้ฟังก์ชันของคุณได้ (หากตรงตามเงื่อนไข)
หากคุณไม่ต้องการใช้สายและประหยัดพื้นที่ของผู้รับสายคุณสามารถใช้เทคนิคทั้งสองนี้ร่วมกัน:
[System.Diagnostics.Conditional("DEBUG")]
public void SetPrivateValue(int value){
#if DEBUG
// method body here
#endif
}
#if DEBUG
ล้อมรอบConditional("DEBUG")
ไม่ได้ลบการเรียกไปยังฟังก์ชันนั้นเพียงแค่ลบฟังก์ชั่นออกจาก IL ทั้งหมดดังนั้นคุณยังคงมีการเรียกไปยังฟังก์ชันที่ไม่มีอยู่ (ข้อผิดพลาดในการรวบรวม)
สมมติว่าโค้ดของคุณมี#else
ข้อความที่กำหนดฟังก์ชั่น null stub โดยระบุหนึ่งในจุดของ Jon Skeet มีความแตกต่างที่สำคัญที่สองระหว่างทั้งสอง
สมมติว่าฟังก์ชัน#if DEBUG
หรือConditional
มีอยู่ใน DLL ซึ่งอ้างอิงโดยปฏิบัติการหลักของโครงการของคุณ การใช้การ#if
ประเมินผลตามเงื่อนไขจะดำเนินการโดยคำนึงถึงการตั้งค่าการรวบรวมของห้องสมุด การใช้Conditional
แอ็ตทริบิวต์การประเมินเงื่อนไขจะดำเนินการตามการตั้งค่าการรวบรวมของผู้เรียกใช้
ฉันมีนามสกุล SOAP [TraceExtension]
เว็บเซอร์เพื่อเข้าสู่ระบบเครือข่ายการจราจรโดยใช้กำหนดเอง ฉันใช้สิ่งนี้เฉพาะกับDebug builds และละเว้นจากRelease builds ใช้การ#if DEBUG
เพื่อล้อมรอบ[TraceExtension]
แอ็ตทริบิวต์เพื่อลบออกจากRelease builds
#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(...)
โดยปกติแล้วคุณจะต้องใช้มันใน Program.cs ที่คุณต้องการเรียกใช้ Debug บนรหัสที่ไม่ใช่ Debug และส่วนใหญ่ใน Windows Services ดังนั้นฉันจึงสร้าง IsDebugMode แบบอ่านอย่างเดียวและตั้งค่าในตัวสร้างสแตติกตามที่แสดงด้านล่าง
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
}