ตรวจสอบวิธีการสร้างและโยนข้อยกเว้นใน C#
- 16 นาที
.NET มีลําดับชั้นของคลาสข้อยกเว้นที่สืบทอดมาจาก System.Exception คลาสพื้นฐาน แอปพลิเคชัน C# สามารถสร้างและโยนข้อยกเว้นประเภทใดก็ได้ นักพัฒนายังสามารถกําหนดวัตถุข้อยกเว้นด้วยข้อมูลเฉพาะของแอปพลิเคชันโดยการกําหนดค่าคุณสมบัติ
หมายเหตุ
โมดูลนี้มุ่งเน้นไปที่การสร้างและโยนข้อยกเว้นและกําหนดออบเจ็กต์ข้อยกเว้น การสร้างคลาสข้อยกเว้นแบบกําหนดเองอยู่นอกขอบเขตของโมดูลนี้
สร้างวัตถุข้อยกเว้น
การสร้างและการโยนข้อยกเว้นจากภายในโค้ดของคุณคือสิ่งสําคัญของการเขียนโปรแกรม C# ความสามารถในการสร้างข้อยกเว้นเพื่อตอบสนองต่อเงื่อนไขปัญหาหรือข้อผิดพลาดเฉพาะช่วยให้คุณมั่นใจถึงความเสถียรของแอปพลิเคชันของคุณ
ชนิดข้อยกเว้นที่คุณสร้างขึ้นจะขึ้นอยู่กับปัญหาการเขียนโค้ด และควรตรงกับวัตถุประสงค์ที่กําหนดของข้อยกเว้นให้ใกล้เคียงที่สุดเท่าที่เป็นไปได้
ตัวอย่างเช่น สมมติว่าคุณกําลังสร้างเมธอดที่ GraphData ชื่อว่า ที่ทําการวิเคราะห์ข้อมูล เมธอด รับอาร์เรย์ข้อมูลเป็นพารามิเตอร์การป้อนข้อมูล วิธีการคาดหวังว่าข้อมูลป้อนเข้าจะอยู่ในช่วงที่เฉพาะเจาะจง หากวิธีการ รับข้อมูลที่อยู่นอกช่วงที่คาดไว้ จะมีการสร้างและแสดงข้อยกเว้นของชนิดArgumentException ข้อยกเว้นจะถูกจัดการในที่ใดที่หนึ่งลงสแตกการโทรโดยโค้ดที่รับผิดชอบในการจัดหาข้อมูล
ต่อไปนี้คือข้อยกเว้นบางประเภททั่วไปที่คุณอาจใช้เมื่อสร้างข้อยกเว้น:
-
ArgumentExceptionหรือArgumentNullException: ใช้ชนิดข้อยกเว้นเหล่านี้เมื่อมีการเรียกเมธอดหรือคอนสตรักเตอร์ด้วยค่าอาร์กิวเมนต์ที่ไม่ถูกต้องหรือการอ้างอิง null -
InvalidOperationException: ใช้ชนิดข้อยกเว้นนี้เมื่อเงื่อนไขการใช้งานของเมธอดไม่สนับสนุนการดําเนินการที่เสร็จสมบูรณ์ของการเรียกเมธอดเฉพาะ -
NotSupportedException: ใช้ชนิดข้อยกเว้นนี้เมื่อไม่สนับสนุนการดําเนินการหรือคุณลักษณะ -
IOException: ใช้ชนิดข้อยกเว้นนี้เมื่อการป้อนข้อมูล/เอาท์พุตล้มเหลว -
FormatException: ใช้ชนิดข้อยกเว้นนี้เมื่อรูปแบบของสตริงหรือข้อมูลไม่ถูกต้อง
คํา new สําคัญถูกใช้เพื่อสร้างอินสแตนซ์ของข้อยกเว้น ตัวอย่างเช่น คุณสามารถสร้างอินสแตนซ์ของ ArgumentException ชนิดข้อยกเว้นดังต่อไปนี้:
ArgumentException invalidArgumentException = new ArgumentException();
กําหนดค่าและโยนข้อยกเว้นแบบกําหนดเอง
กระบวนการสําหรับการขว้างอวัตถุข้อยกเว้นเกี่ยวข้องกับการสร้างอินสแตนซ์ของคลาสที่ได้รับข้อยกเว้น เป็นทางเลือกที่จะกําหนดค่าคุณสมบัติของข้อยกเว้น จากนั้นจึงขว้างออบเจ็กต์โดยใช้ throw คําสําคัญ
การปรับแต่งข้อยกเว้นด้วยข้อมูลตามบริบทก่อนที่จะถูกโยนมักจะเป็นประโยชน์ คุณสามารถให้ข้อมูลเฉพาะของแอปพลิเคชันภายในออบเจ็กต์ข้อยกเว้นได้โดยการกําหนดค่าคุณสมบัติ ตัวอย่างเช่น โค้ดต่อไปนี้สร้างออบเจ็กต์ข้อยกเว้นที่ invalidArgumentException ชื่อด้วยคุณสมบัติแบบกําหนดเอง Message จากนั้นจึงแสดงข้อยกเว้น:
ArgumentException invalidArgumentException = new ArgumentException("ArgumentException: The 'GraphData' method received data outside the expected range.");
throw invalidArgumentException;
หมายเหตุ
คุณสมบัติของ Message ข้อยกเว้นเป็นแบบอ่านอย่างเดียว ดังนั้น ต้องตั้งค่าคุณสมบัติแบบกําหนดเอง Message เมื่อมีการสร้างอินสแตนซ์ของวัตถุ
เมื่อกําหนดวัตถุข้อยกเว้น เป็นสิ่งสําคัญที่จะต้องระบุข้อความแสดงข้อผิดพลาดที่ชัดเจนที่อธิบายปัญหาและวิธีแก้ไขปัญหา คุณยังสามารถใส่ข้อมูลเพิ่มเติม เช่น การติดตามสแตกและรหัสข้อผิดพลาด เพื่อช่วยให้ผู้ใช้สามารถแก้ไขปัญหาได้
นอกจากนี้ คุณยังสามารถสร้างออบเจ็กต์ข้อยกเว้นได้โดยตรงภายใน throw คําสั่ง เช่น:
throw new FormatException("FormatException: Calculations in process XYZ have been cancelled due to invalid data format.");
ข้อควรพิจารณาบางประการที่ควรทราบเมื่อโยนข้อยกเว้น:
- คุณสมบัติ
Messageควรอธิบายเหตุผลสําหรับข้อยกเว้น อย่างไรก็ตาม ข้อมูลที่ละเอียดอ่อนหรือที่แสดงถึงข้อกังวลด้านความปลอดภัยไม่ควรใส่ในข้อความ - คุณสมบัติ
StackTraceมักใช้เพื่อติดตามจุดเริ่มต้นของข้อยกเว้น คุณสมบัติสตริงนี้ประกอบด้วยชื่อของเมธอดบนสแตกการเรียกปัจจุบันพร้อมกับชื่อไฟล์และหมายเลขบรรทัดในแต่ละวิธีที่เชื่อมโยงกับข้อยกเว้น ออบเจ็กต์StackTraceจะถูกสร้างขึ้นโดยอัตโนมัติโดยรันไทม์ภาษาทั่วไป (CLR) จากจุดของthrowคําสั่ง ข้อยกเว้นต้องถูกโยนจากจุดที่ควรเริ่มต้นการติดตามสแตก
เมื่อต้องการโยนข้อยกเว้น
วิธีการควรโยนข้อยกเว้นเมื่อใดก็ตามที่พวกเขาไม่สามารถดําเนินการตามวัตถุประสงค์ที่ตั้งใจไว้ให้เสร็จสมบูรณ์ได้ ข้อยกเว้นที่โยนควรจะยึดตามข้อยกเว้นเฉพาะเจาะจงมากที่สุดที่พร้อมใช้งานซึ่งเหมาะสมกับเงื่อนไขข้อผิดพลาด
พิจารณาสถานการณ์ที่นักพัฒนากําลังทํางานกับแอปพลิเคชันที่ใช้กระบวนการทางธุรกิจ กระบวนการทางธุรกิจจะขึ้นอยู่กับการป้อนข้อมูลของผู้ใช้ หากข้อมูลป้อนเข้าไม่ตรงกับชนิดข้อมูลที่คาดไว้ วิธีการที่ใช้กระบวนการทางธุรกิจจะสร้างและแสดงข้อยกเว้น วัตถุข้อยกเว้นสามารถกําหนดค่าด้วยข้อมูลเฉพาะของแอปพลิเคชันในค่าคุณสมบัติ ตัวอย่างโค้ดต่อไปนี้แสดงให้เห็นถึงสถานการณ์:
string[][] userEnteredValues = new string[][]
{
new string[] { "1", "two", "3"},
new string[] { "0", "1", "2"}
};
foreach (string[] userEntries in userEnteredValues)
{
try
{
BusinessProcess1(userEntries);
}
catch (Exception ex)
{
if (ex.StackTrace.Contains("BusinessProcess1") && (ex is FormatException))
{
Console.WriteLine(ex.Message);
}
}
}
static void BusinessProcess1(string[] userEntries)
{
int valueEntered;
foreach (string userValue in userEntries)
{
try
{
valueEntered = int.Parse(userValue);
// completes required calculations based on userValue
// ...
}
catch (FormatException)
{
FormatException invalidFormatException = new FormatException("FormatException: User input values in 'BusinessProcess1' must be valid integers");
throw invalidFormatException;
}
}
}
ในตัวอย่างรหัสนี้ คําสั่งระดับบนสุดจะ BusinessProcess1 เรียกใช้เมธอด ซึ่งส่งผ่านในอาร์เรย์สตริงที่ประกอบด้วยค่าที่ผู้ใช้ป้อน เม BusinessProcess1 ธอด คาดหวังค่าอินพุตของผู้ใช้ที่สามารถแปลงเป็นจํานวนเต็มได้ เมื่อเมธอดพบข้อมูลที่มีรูปแบบที่ไม่ถูกต้อง จะสร้างอินสแตนซ์ของFormatExceptionชนิดข้อยกเว้นโดยใช้คุณสมบัติที่กําหนดเองMessage จากนั้นเมธอด จะแสดงข้อยกเว้น ข้อยกเว้นถูกจับได้ในคําสั่งระดับบนสุดเป็นออบเจ็กต์ที่ชื่อว่าex
exคุณสมบัติของวัตถุจะถูกตรวจสอบก่อนที่จะแสดงข้อความข้อยกเว้นให้ผู้ใช้ ก่อนอื่น รหัสตรวจสอบ StackTrace คุณสมบัติเพื่อดูว่ามี "BusinessProcess1" อยู่หรือไม่ ประการที่สอง วัตถุexข้อยกเว้นได้รับการตรวจสอบเป็นชนิดFormatException
ข้อยกเว้นการโยนอีกครั้ง
นอกเหนือจากการโยนข้อยกเว้น throw ใหม่สามารถใช้โยนข้อยกเว้นจากภายใน catch บล็อกรหัสได้อีกครั้ง ในกรณีนี้ throw ไม่ได้ใช้ตัวถูกดําเนินการข้อยกเว้น
catch (Exception ex)
{
// handle or partially handle the exception
// ...
// re-throw the original exception object for further handling down the call stack
throw;
}
เมื่อคุณโยนข้อยกเว้นอีกครั้ง มีการใช้ออบเจ็กต์ข้อยกเว้นต้นฉบับ ดังนั้นคุณจะไม่สูญเสียข้อมูลใดๆ เกี่ยวกับข้อยกเว้น ถ้าคุณต้องการสร้างวัตถุข้อยกเว้นใหม่ที่ครอบคลุมข้อยกเว้นเดิม คุณสามารถส่งผ่านข้อยกเว้นเดิมเป็นอาร์กิวเมนต์ไปยังคอนสตรักเตอร์ของวัตถุข้อยกเว้นใหม่ได้ เช่น:
catch (Exception ex)
{
// handle or partially handle the exception
// ...
// create a new exception object that wraps the original exception
throw new ApplicationException("An error occurred", ex);
}
สําหรับสถานการณ์แอปพลิเคชัน "BusinessProcess1" ให้พิจารณาการอัปเดตต่อไปนี้:
- มี
BusinessProcess1การอัปเดตวิธีการ เพื่อรวมรายละเอียดเพิ่มเติมBusinessProcess1ขณะนี้พบสองปัญหาและต้องสร้างข้อยกเว้นสําหรับแต่ละปัญหา - รายงานระดับบนสุดได้รับการอัปเดตแล้ว ตอนนี้คําสั่งระดับบนสุดจะ
OperatingProcedure1เรียกใช้เมธอดOperatingProcedure1เรียกBusinessProcess1ภายในบล็อกtryรหัส - เม
OperatingProcedure1ธอด สามารถจัดการประเภทข้อยกเว้นชนิดหนึ่งและจัดการส่วนอื่นบางส่วนได้ เมื่อประมวลผลOperatingProcedure1ข้อยกเว้นที่จัดการบางส่วนแล้ว ต้องโยนข้อยกเว้นเดิมอีกครั้ง
ตัวอย่างโค้ดต่อไปนี้แสดงให้เห็นถึงสถานการณ์ที่อัปเดตแล้ว:
try
{
OperatingProcedure1();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Exiting application.");
}
static void OperatingProcedure1()
{
string[][] userEnteredValues = new string[][]
{
new string[] { "1", "two", "3"},
new string[] { "0", "1", "2"}
};
foreach(string[] userEntries in userEnteredValues)
{
try
{
BusinessProcess1(userEntries);
}
catch (Exception ex)
{
if (ex.StackTrace.Contains("BusinessProcess1"))
{
if (ex is FormatException)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Corrective action taken in OperatingProcedure1");
}
else if (ex is DivideByZeroException)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Partial correction in OperatingProcedure1 - further action required");
// re-throw the original exception
throw;
}
else
{
// create a new exception object that wraps the original exception
throw new ApplicationException("An error occurred - ", ex);
}
}
}
}
}
static void BusinessProcess1(string[] userEntries)
{
int valueEntered;
foreach (string userValue in userEntries)
{
try
{
valueEntered = int.Parse(userValue);
checked
{
int calculatedValue = 4 / valueEntered;
}
}
catch (FormatException)
{
FormatException invalidFormatException = new FormatException("FormatException: User input values in 'BusinessProcess1' must be valid integers");
throw invalidFormatException;
}
catch (DivideByZeroException)
{
DivideByZeroException unexpectedDivideByZeroException = new DivideByZeroException("DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero");
throw unexpectedDivideByZeroException;
}
}
}
รหัสตัวอย่างที่อัปเดตแล้วจะสร้างเอาต์พุตต่อไปนี้:
FormatException: User input values in 'BusinessProcess1' must be valid integers
Corrective action taken in OperatingProcedure1
DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero
Partial correction in OperatingProcedure1 - further action required
DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero
Exiting application.
สิ่งที่ต้องหลีกเลี่ยงเมื่อขว้างข้อยกเว้น
รายการต่อไปนี้ระบุแนวทางปฏิบัติที่จะหลีกเลี่ยงเมื่อโยนข้อยกเว้น:
- อย่าใช้ข้อยกเว้นเพื่อเปลี่ยนโฟลว์ของโปรแกรมให้เป็นส่วนหนึ่งของการดําเนินการทั่วไป ใช้ข้อยกเว้นเพื่อรายงานและจัดการเงื่อนไขของข้อผิดพลาด
- ไม่ควรส่งกลับข้อยกเว้นเป็นค่าที่ส่งกลับหรือพารามิเตอร์แทนที่จะถูกโยน
- อย่าโยน
System.ExceptionSystem.SystemException,System.NullReferenceException, หรือSystem.IndexOutOfRangeExceptionโดยเจตนาจากโค้ดต้นฉบับของคุณเอง - อย่าสร้างข้อยกเว้นที่สามารถแสดงในโหมดดีบัก แต่ไม่สร้างโหมดนําออกใช้ เมื่อต้องการระบุข้อผิดพลาดรันไทม์ในระหว่างขั้นตอนการพัฒนา ให้ใช้
Debug.Assertแทน
หมายเหตุ
เม Debug.Assert ธอด เป็นเครื่องมือในการตรวจจับข้อผิดพลาดทางตรรกะในระหว่างการพัฒนา ตามค่าเริ่มต้น วิธีการ จะ Debug.Assert ทํางานเฉพาะในดีบักบิลบิลเท่านั้น คุณสามารถใช้ Debug.Assert ในเซสชันดีบักเพื่อตรวจสอบเงื่อนไขที่ไม่ควรเกิดขึ้น เมธอด จะใช้พารามิเตอร์สองตัว: เงื่อนไขบูลีนเพื่อตรวจสอบ และข้อความสตริงทางเลือกที่จะแสดงหากเงื่อนไขคือfalse
Debug.Assert ไม่ควรใช้แทนการโยนข้อยกเว้น ซึ่งเป็นวิธีในการจัดการสถานการณ์พิเศษระหว่างการดําเนินการรหัสของคุณตามปกติ คุณควรใช้ Debug.Assert เพื่อตรวจจับข้อผิดพลาดที่ไม่ควรเกิดขึ้น และใช้ข้อยกเว้นในการจัดการข้อผิดพลาดที่อาจเกิดขึ้นระหว่างการดําเนินการปกติของโปรแกรมของคุณ
สรุป
นี่คือสิ่งสําคัญบางอย่างที่ต้องจําจากหน่วยนี้:
- เมื่อสร้างและโยนข้อยกเว้น ประเภทข้อยกเว้นต้องตรงกับวัตถุประสงค์ที่กําหนดไว้ของข้อยกเว้นโดยใกล้เคียงที่สุดเท่าที่เป็นไปได้
-
throwสําหรับข้อยกเว้น คุณต้องสร้างอินสแตนซ์ของคลาสที่ได้รับข้อยกเว้น กําหนดค่าคุณสมบัติ จากนั้นใช้throwคําสําคัญ - เมื่อสร้างวัตถุข้อยกเว้น เป็นสิ่งสําคัญที่จะต้องระบุข้อความแสดงข้อผิดพลาดที่ชัดเจนและข้อมูลเพิ่มเติมเพื่อช่วยให้ผู้ใช้แก้ไขปัญหาได้
ตรวจสอบความรู้ของคุณ
คำติชม
หน้านี้มีประโยชน์หรือไม่
ไม่
ต้องการความช่วยเหลือในหัวข้อนี้หรือไม่
ต้องการลองใช้ Ask Learn เพื่อทําให้ชัดเจนหรือแนะนําคุณผ่านหัวข้อนี้หรือไม่