ดังนั้นฉันรู้ว่า try / catch เพิ่มค่าใช้จ่ายบางส่วนดังนั้นจึงไม่ใช่วิธีที่ดีในการควบคุมโฟลว์กระบวนการ แต่ค่าใช้จ่ายนี้มาจากไหนและผลกระทบที่แท้จริงคืออะไร
ดังนั้นฉันรู้ว่า try / catch เพิ่มค่าใช้จ่ายบางส่วนดังนั้นจึงไม่ใช่วิธีที่ดีในการควบคุมโฟลว์กระบวนการ แต่ค่าใช้จ่ายนี้มาจากไหนและผลกระทบที่แท้จริงคืออะไร
คำตอบ:
ฉันไม่ใช่ผู้เชี่ยวชาญในการใช้งานภาษา (ดังนั้นควรใช้สิ่งนี้ด้วยเกลือเม็ด) แต่ฉันคิดว่าหนึ่งในต้นทุนที่ใหญ่ที่สุดคือการคลายสแต็กและเก็บไว้สำหรับการติดตามสแต็ก ฉันสงสัยว่าสิ่งนี้จะเกิดขึ้นก็ต่อเมื่อมีการโยนข้อยกเว้น (แต่ฉันไม่รู้) และถ้าเป็นเช่นนั้นนี่จะเป็นต้นทุนแฝงที่เหมาะสมทุกครั้งที่มีการโยนข้อยกเว้น ... ดังนั้นจึงไม่เหมือนกับว่าคุณกำลังกระโดดจากที่เดียว ในรหัสไปยังอีกรหัสหนึ่งมีจำนวนมากเกิดขึ้น
ฉันไม่คิดว่ามันจะเป็นปัญหาตราบใดที่คุณใช้ข้อยกเว้นสำหรับพฤติกรรม EXCEPTIONAL (ไม่ใช่เส้นทางปกติที่คุณคาดหวังผ่านโปรแกรม)
สามจุดที่ต้องทำที่นี่:
ประการแรกมีโทษด้านประสิทธิภาพเพียงเล็กน้อยหรือไม่มีเลยในการมีบล็อกการลองจับในโค้ดของคุณ สิ่งนี้ไม่ควรนำมาพิจารณาเมื่อพยายามหลีกเลี่ยงไม่ให้มีอยู่ในแอปพลิเคชันของคุณ การตีประสิทธิภาพจะเกิดขึ้นเมื่อมีข้อยกเว้นเกิดขึ้นเท่านั้น
เมื่อเกิดข้อยกเว้นนอกเหนือไปจากการดำเนินการคลี่คลายสแต็ก ฯลฯ ที่เกิดขึ้นซึ่งคนอื่นกล่าวถึงคุณควรทราบว่าสิ่งที่เกี่ยวข้องกับรันไทม์ / การสะท้อนทั้งหมดเกิดขึ้นเพื่อเติมข้อมูลสมาชิกของคลาสข้อยกเว้นเช่นการติดตามสแต็ก วัตถุและสมาชิกประเภทต่างๆเป็นต้น
ฉันเชื่อว่านี่เป็นหนึ่งในเหตุผลที่คำแนะนำทั่วไปหากคุณกำลังจะยกเลิกข้อยกเว้นคือเพียงแค่throw;
โยนข้อยกเว้นอีกครั้งหรือสร้างข้อยกเว้นใหม่ในกรณีเหล่านั้นข้อมูลสแต็กทั้งหมดจะถูกรวบรวมในขณะที่ในวิธีง่ายๆ โยนมันถูกเก็บรักษาไว้ทั้งหมด
throw new Exception("Wrapping layer’s error", ex);
คุณกำลังถามเกี่ยวกับค่าใช้จ่ายในการใช้ try / catch / ในที่สุดเมื่อไม่มีการโยนข้อยกเว้นหรือค่าใช้จ่ายในการใช้ข้อยกเว้นเพื่อควบคุมการไหลของกระบวนการ? อย่างหลังนี้ค่อนข้างคล้ายกับการใช้แท่งดินระเบิดเพื่อจุดเทียนวันเกิดของเด็กวัยหัดเดินและค่าใช้จ่ายที่เกี่ยวข้องจะตกอยู่ในพื้นที่ต่อไปนี้:
คุณสามารถคาดหวังความผิดพลาดของเพจเพิ่มเติมเนื่องจากข้อยกเว้นที่ถูกโยนเข้าไปในการเข้าถึงรหัสที่ไม่มีถิ่นที่อยู่และข้อมูลที่ไม่อยู่ในชุดการทำงานของแอปพลิเคชัน
โดยทั่วไปทั้งสองรายการข้างต้นจะเข้าถึงรหัสและข้อมูล "เย็น" ดังนั้นข้อบกพร่องของฮาร์ดเพจจึงน่าจะเกิดขึ้นได้หากคุณมีความกดดันด้านหน่วยความจำเลย:
สำหรับผลกระทบที่แท้จริงของค่าใช้จ่ายสิ่งนี้อาจแตกต่างกันไปมากขึ้นอยู่กับสิ่งที่เกิดขึ้นในรหัสของคุณในขณะนั้น Jon Skeet มีบทสรุปที่ดีที่นี่พร้อมลิงก์ที่เป็นประโยชน์ ฉันมักจะเห็นด้วยกับคำพูดของเขาที่ว่าหากคุณไปถึงจุดที่มีข้อยกเว้นที่ส่งผลเสียต่อประสิทธิภาพของคุณอย่างมากคุณจะมีปัญหาในแง่ของการใช้ข้อยกเว้นนอกเหนือจากประสิทธิภาพ
จากประสบการณ์ของฉันค่าใช้จ่ายที่ใหญ่ที่สุดคือการทิ้งข้อยกเว้นและจัดการกับมัน ครั้งหนึ่งฉันเคยทำงานในโครงการที่มีการใช้รหัสที่คล้ายกับสิ่งต่อไปนี้เพื่อตรวจสอบว่ามีใครมีสิทธิ์แก้ไขวัตถุบางอย่างหรือไม่ วิธี HasRight () นี้ถูกใช้ทุกที่ในเลเยอร์การนำเสนอและมักถูกเรียกใช้สำหรับวัตถุ 100 ชิ้น
bool HasRight(string rightName, DomainObject obj) {
try {
CheckRight(rightName, obj);
return true;
}
catch (Exception ex) {
return false;
}
}
void CheckRight(string rightName, DomainObject obj) {
if (!_user.Rights.Contains(rightName))
throw new Exception();
}
เมื่อฐานข้อมูลทดสอบเต็มไปด้วยข้อมูลทดสอบสิ่งนี้จะนำไปสู่การชะลอตัวที่มองเห็นได้ชัดเจนในขณะที่เปิดรูปแบบใหม่เป็นต้น
ดังนั้นฉันจึงปรับโครงสร้างใหม่เป็นสิ่งต่อไปนี้ซึ่ง - ตามการวัดอย่างรวดเร็ว 'n สกปรกในภายหลัง - มีขนาดเร็วขึ้นประมาณ 2 คำสั่ง:
bool HasRight(string rightName, DomainObject obj) {
return _user.Rights.Contains(rightName);
}
void CheckRight(string rightName, DomainObject obj) {
if (!HasRight(rightName, obj))
throw new Exception();
}
ดังนั้นในระยะสั้นการใช้ข้อยกเว้นในโฟลว์กระบวนการปกติจะมีขนาดประมาณสองลำดับที่ช้าลงจากนั้นใช้โฟลว์กระบวนการที่คล้ายกันโดยไม่มีข้อยกเว้น
ตรงกันข้ามกับทฤษฎีที่ยอมรับกันทั่วไปtry
/ catch
อาจมีผลกระทบอย่างมีนัยสำคัญและนั่นอาจเป็นข้อยกเว้นหรือไม่!
ก่อนหน้านี้ได้รับการกล่าวถึงในบล็อกโพสต์สองสามรายการโดย Microsoft MVP ในช่วงหลายปีที่ผ่านมาและฉันเชื่อว่าคุณสามารถค้นหาได้อย่างง่ายดาย แต่ StackOverflow ก็ใส่ใจ ให้กับเนื้อหามากดังนั้นฉันจะให้ลิงก์ไปยังบางส่วนเพื่อเป็นหลักฐานการเติม :
try
/ catch
/finally
( และส่วนที่สอง ) โดย Peter Ritchie สำรวจการเพิ่มประสิทธิภาพที่try
/ catch
/ finally
ปิดใช้งาน (และฉันจะพูดถึงเรื่องนี้เพิ่มเติมด้วยคำพูดจากมาตรฐาน)Parse
เทียบTryParse
กับConvertTo
โดยเอียนฮัฟฟ์ระบุอย่างโจ่งแจ้งว่า "การจัดการข้อยกเว้นช้ามาก" และแสดงให้เห็นถึงประเด็นนี้โดยการเจาะInt.Parse
และInt.TryParse
ต่อกัน ... สำหรับทุกคนที่ยืนยันว่าTryParse
ใช้try
/ catch
อยู่เบื้องหลังสิ่งนี้ควรทำให้กระจ่าง!นอกจากนี้ยังมีคำตอบนี้ซึ่งแสดงให้เห็นความแตกต่างระหว่างรหัส disassembled with- และโดยไม่ต้องใช้/try
catch
ดูเหมือนชัดเจนมากที่นั่น เป็นค่าใช้จ่ายซึ่งเป็นที่สังเกตได้อย่างโจ๋งครึ่มในการสร้างรหัสและค่าใช้จ่ายว่าแม้ดูเหมือนว่าจะได้รับการยอมรับจากคนที่คุ้มค่าไมโครซอฟท์! แต่ฉันกำลังเล่นอินเทอร์เน็ตซ้ำ ...
ใช่มีคำแนะนำ MSIL เพิ่มเติมมากมายสำหรับโค้ดบรรทัดเดียวที่ไม่สำคัญและไม่ครอบคลุมถึงการเพิ่มประสิทธิภาพที่ปิดใช้งานดังนั้นในทางเทคนิคจึงเป็นการเพิ่มประสิทธิภาพระดับไมโคร
ฉันโพสต์คำตอบเมื่อหลายปีก่อนซึ่งถูกลบเนื่องจากมุ่งเน้นไปที่ผลผลิตของโปรแกรมเมอร์ (การเพิ่มประสิทธิภาพมาโคร)
นี่เป็นเรื่องที่โชคร้ายเนื่องจากไม่มีการประหยัดเวลาเพียงไม่กี่นาโนวินาทีที่นี่และเวลาของ CPU มีแนวโน้มที่จะชดเชยเป็นเวลาหลายชั่วโมงในการเพิ่มประสิทธิภาพด้วยตนเองโดยมนุษย์ เจ้านายของคุณจ่ายค่าอะไรมากกว่า: ชั่วโมงของคุณหรือหนึ่งชั่วโมงในขณะที่คอมพิวเตอร์ทำงาน? เมื่อถึงจุดใดที่เราดึงปลั๊กและยอมรับว่าถึงเวลาที่จะต้องซื้อคอมพิวเตอร์ที่เร็วขึ้น ?
เห็นได้ชัดว่าเราควรปรับลำดับความสำคัญของเราให้เหมาะสมให้เหมาะสมไม่ใช่แค่โค้ดของเรา! ในคำตอบสุดท้ายของฉันฉันได้พิจารณาถึงความแตกต่างระหว่างสองส่วนย่อยของโค้ด
ใช้try
/ catch
:
int x;
try {
x = int.Parse("1234");
}
catch {
return;
}
// some more code here...
ไม่ใช้try
/ catch
:
int x;
if (int.TryParse("1234", out x) == false) {
return;
}
// some more code here
พิจารณาจากมุมมองของผู้พัฒนาด้านการบำรุงรักษาซึ่งมีแนวโน้มที่จะเสียเวลาของคุณหากไม่ได้อยู่ในการทำโปรไฟล์ / การปรับให้เหมาะสม (กล่าวถึงด้านบน) ซึ่งอาจไม่จำเป็นด้วยซ้ำหากไม่ใช่สำหรับtry
/ catch
ปัญหาจากนั้นในการเลื่อนดู ซอร์สโค้ด ... หนึ่งในนั้นมีขยะสำเร็จรูปสี่บรรทัด!
เมื่อมีการนำฟิลด์เข้ามาในชั้นเรียนมากขึ้นเรื่อย ๆ ขยะสำเร็จรูปทั้งหมดนี้จะสะสม (ทั้งในรหัสต้นทางและรหัสแยกชิ้นส่วน) เกินระดับที่เหมาะสม สี่บรรทัดต่อสนามและมันเป็นบรรทัดเดียวกันเสมอ ... เราไม่ได้รับการสอนให้หลีกเลี่ยงการทำซ้ำตัวเองหรือ? ฉันคิดว่าเราสามารถซ่อนtry
/catch
เบื้องหลังนามธรรมที่ชงเองที่บ้านได้ แต่ ... จากนั้นเราก็อาจหลีกเลี่ยงข้อยกเว้น (เช่นใช้Int.TryParse
)
นี่ไม่ใช่ตัวอย่างที่ซับซ้อน ฉันเคยเห็นความพยายามในการสร้างอินสแตนซ์คลาสใหม่ในtry
/ catch
. พิจารณาว่าโค้ดทั้งหมดภายในตัวสร้างอาจถูกตัดสิทธิ์จากการเพิ่มประสิทธิภาพบางอย่างที่คอมไพเลอร์จะนำไปใช้โดยอัตโนมัติ จะมีอะไรดีไปกว่าการทำให้เกิดทฤษฎีที่คอมไพเลอร์ช้าเมื่อเทียบกับคอมไพเลอร์จะทำสิ่งที่มันบอกว่าจะทำอย่างไร ?
สมมติว่ามีข้อยกเว้นเกิดขึ้นโดยตัวสร้างดังกล่าวและข้อผิดพลาดบางอย่างถูกทริกเกอร์ด้วยเหตุนี้ผู้พัฒนาด้านการบำรุงรักษาที่ไม่ดีจะต้องติดตามมัน นั่นอาจไม่ใช่เรื่องง่ายเช่นนี้ซึ่งแตกต่างจากรหัสสปาเก็ตตี้ของgoto nightmare try
/ catch
อาจทำให้เกิดความยุ่งเหยิงในสามมิติเนื่องจากสามารถเลื่อนสแต็กขึ้นไปไม่ใช่แค่ส่วนอื่น ๆ ของวิธีการเดียวกัน แต่ยังรวมถึงคลาสและวิธีการอื่น ๆ ด้วย ซึ่งทั้งหมดนี้จะถูกสังเกตโดยผู้พัฒนาด้านการบำรุงรักษาวิธีที่ยาก ! ยังมีคนบอกว่า "goto อันตราย" หึ!
ในตอนท้ายฉันพูดถึงtry
/ catch
มีประโยชน์ซึ่งออกแบบมาเพื่อปิดการใช้งานการเพิ่มประสิทธิภาพ ! ถ้าคุณจะช่วยแก้จุดบกพร่อง ! นั่นคือสิ่งที่ออกแบบมาสำหรับและเป็นสิ่งที่ควรใช้เป็น ...
ฉันเดาว่านั่นเป็นจุดบวกเช่นกัน สามารถใช้เพื่อปิดใช้งานการเพิ่มประสิทธิภาพที่อาจทำให้อัลกอริธึมการส่งข้อความที่ปลอดภัยและปลอดภัยสำหรับแอปพลิเคชันแบบมัลติเธรดและเพื่อตรวจจับสภาพการแข่งขันที่เป็นไปได้;) นั่นเป็นเพียงสถานการณ์เดียวที่ฉันคิดได้ว่าจะใช้ try / catch แม้จะมีทางเลือกอื่น
optimisations ทำอะไรtry
, catch
และfinally
ปิดการใช้งาน?
อาคา
เป็นอย่างไรtry
, catch
และfinally
เป็นประโยชน์ในการแก้จุดบกพร่องโรคเอดส์?
เป็นอุปสรรคในการเขียน สิ่งนี้มาจากมาตรฐาน:
12.3.3.13 งบทดลองจับ
สำหรับคำสั่งstmtของแบบฟอร์ม:
try try-block catch ( ... ) catch-block-1 ... catch ( ... ) catch-block-n
- รัฐที่ได้รับมอบหมายที่ชัดเจนของโวลต์ที่จุดเริ่มต้นของการพยายามบล็อกเป็นเช่นเดียวกับรัฐที่ได้รับมอบหมายที่ชัดเจนของโวลต์ที่จุดเริ่มต้นของstmt
- รัฐที่ได้รับมอบหมายที่ชัดเจนของโวลต์ที่จุดเริ่มต้นของการจับบล็อก-I (สำหรับผม ) เป็นเช่นเดียวกับรัฐที่ได้รับมอบหมายที่ชัดเจนของโวลต์ที่จุดเริ่มต้นของstmt
- สถานะการกำหนดที่แน่นอนของvที่จุดสิ้นสุดของstmtถูกกำหนดอย่างแน่นอนถ้า (และเฉพาะในกรณีที่) vถูกกำหนดอย่างแน่นอนที่จุดสิ้นสุดของtry-blockและทุกๆcatch-block-i (สำหรับทุกๆiตั้งแต่ 1 ถึงn ).
กล่าวอีกนัยหนึ่งในตอนต้นของแต่ละtry
คำสั่ง:
try
คำสั่งจะต้องเสร็จสมบูรณ์ซึ่งต้องมีการล็อกเธรดสำหรับการเริ่มต้นทำให้มีประโยชน์สำหรับการดีบักเงื่อนไขการแข่งขัน!try
คำสั่งเรื่องราวที่คล้ายกันถือไว้สำหรับแต่ละcatch
คำสั่ง สมมติว่าในtry
คำสั่งของคุณ(หรือตัวสร้างหรือฟังก์ชันที่เรียกใช้ ฯลฯ ) ที่คุณกำหนดให้กับตัวแปรที่ไม่มีจุดหมายนั้น (สมมติว่าgarbage=42;
) คอมไพเลอร์ไม่สามารถกำจัดคำสั่งนั้นได้ไม่ว่ามันจะไม่เกี่ยวข้องกับพฤติกรรมที่สังเกตได้ของโปรแกรมก็ตาม . งานจะต้องเสร็จสิ้นก่อนที่catch
จะเข้าสู่บล็อก
สำหรับสิ่งที่คุ้มค่าfinally
เล่าเรื่องราวที่เสื่อมโทรมในทำนองเดียวกัน:
12.3.3.14 งบทดลองในที่สุด
สำหรับคำสั่งtry stmtของแบบฟอร์ม:
try try-block finally finally-block
•รัฐมอบหมายชัดเจนของโวลต์ ที่จุดเริ่มต้นของการพยายามบล็อกเป็นเช่นเดียวกับรัฐมอบหมายชัดเจนของโวลต์ที่จุดเริ่มต้นของstmt
•รัฐมอบหมายชัดเจนของโวลต์ที่จุดเริ่มต้นของที่สุดบล็อกเป็นเช่นเดียวกับรัฐมอบหมายชัดเจนของโวลต์ที่จุดเริ่มต้นของstmt
•สถานะการกำหนดที่แน่นอนของvที่จุดสิ้นสุดของstmtถูกกำหนดอย่างแน่นอนถ้า (และเฉพาะในกรณีที่) อย่างใดอย่างหนึ่ง: o vถูกกำหนดที่จุดสิ้นสุดของtry-block o vได้รับมอบหมายอย่างแน่นอนที่จุดสิ้นสุดของบล็อกสุดท้าย หากมีการถ่ายโอนโฟลว์การควบคุม (เช่นคำสั่งgoto ) ที่เริ่มต้นภายในบล็อกการลองและสิ้นสุดนอกบล็อกการลองดังนั้นvจะถือว่าได้รับมอบหมายอย่างแน่นอน ควบคุมการถ่ายโอนการไหลถ้าโวลต์ได้รับมอบหมายแน่นอนที่จุดสิ้นสุดของที่สุดบล็อก (นี่ไม่ใช่เฉพาะในกรณีที่ - ถ้าvถูกกำหนดอย่างแน่นอนด้วยเหตุผลอื่นในการถ่ายโอนโฟลว์การควบคุมนี้ก็ยังถือว่าได้รับมอบหมายอย่างแน่นอน)
12.3.3.15 งบทดลองในที่สุด
การวิเคราะห์การมอบหมายงานที่ชัดเจนสำหรับคำสั่งtry - catch - สุดท้ายของแบบฟอร์ม:
try try-block catch ( ... ) catch-block-1 ... catch ( ... ) catch-block-n finally finally-block
จะทำราวกับว่าคำสั่งนั้นเป็นคำสั่งtry - ในที่สุดคำสั่งที่แนบคำสั่งtry - catch :
try { try try-block catch ( ... ) catch-block-1 ... catch ( ... ) catch-block-n } finally finally-block
ไม่ต้องพูดถึงว่าอยู่ในวิธีการที่เรียกบ่อยหรือไม่อาจส่งผลต่อพฤติกรรมโดยรวมของแอปพลิเคชัน
ตัวอย่างเช่นฉันถือว่าการใช้ Int32 ถือว่าเป็นการปฏิบัติที่ไม่ดีในกรณีส่วนใหญ่เนื่องจากมีข้อยกเว้นสำหรับสิ่งที่สามารถจับได้ง่าย
ดังนั้นเพื่อสรุปทุกสิ่งที่เขียนไว้ที่นี่:
1) ใช้ try..catch บล็อคเพื่อตรวจจับข้อผิดพลาดที่ไม่คาดคิด - แทบจะไม่มีการลงโทษด้านประสิทธิภาพ
2) อย่าใช้ข้อยกเว้นสำหรับข้อผิดพลาดที่ยกเว้นหากคุณสามารถหลีกเลี่ยงได้
ฉันเขียนบทความเกี่ยวกับเรื่องนี้มาสักพักแล้วเพราะมีคนถามเกี่ยวกับเรื่องนี้เป็นจำนวนมากในเวลานั้น คุณสามารถค้นหาและรหัสการทดสอบที่http://www.blackwasp.co.uk/SpeedTestTryCatch.aspx
ผลที่สุดคือมีค่าใช้จ่ายจำนวนเล็กน้อยสำหรับบล็อก try / catch แต่มีขนาดเล็กมากจนควรละเว้น อย่างไรก็ตามหากคุณกำลังเรียกใช้บล็อก try / catch ในลูปที่ดำเนินการหลายล้านครั้งคุณอาจต้องการพิจารณาย้ายบล็อกไปนอกลูปถ้าเป็นไปได้
ปัญหาด้านประสิทธิภาพที่สำคัญของบล็อก try / catch คือเมื่อคุณพบข้อยกเว้นจริง ซึ่งอาจเพิ่มความล่าช้าอย่างเห็นได้ชัดให้กับแอปพลิเคชันของคุณ แน่นอนว่าเมื่อเกิดความผิดพลาดนักพัฒนาส่วนใหญ่ (และผู้ใช้จำนวนมาก) รับรู้ว่าการหยุดชั่วคราวเป็นข้อยกเว้นที่กำลังจะเกิดขึ้น! กุญแจสำคัญในที่นี้คือไม่ใช้การจัดการข้อยกเว้นสำหรับการทำงานปกติ ตามชื่อที่แนะนำมันยอดเยี่ยมมากและคุณควรทำทุกอย่างที่ทำได้เพื่อหลีกเลี่ยงไม่ให้พวกมันถูกโยน คุณไม่ควรใช้เป็นส่วนหนึ่งของขั้นตอนที่คาดไว้ของโปรแกรมที่ทำงานได้อย่างถูกต้อง
ฉันทำรายการบล็อกเกี่ยวกับเรื่องนี้เมื่อปีที่แล้ว ลองดูสิ บรรทัดล่างคือแทบจะไม่มีค่าใช้จ่ายสำหรับการลองบล็อกหากไม่มีข้อยกเว้นเกิดขึ้น - และบนแล็ปท็อปของฉันมีข้อยกเว้นประมาณ36μs ซึ่งอาจน้อยกว่าที่คุณคาดไว้ แต่โปรดทราบว่าผลลัพธ์เหล่านั้นอยู่ในสแต็กตื้น นอกจากนี้ข้อยกเว้นแรกช้ามาก
try
/ catch
มากเกินไปหรือเปล่าหึหึหึ) แต่ดูเหมือนว่าคุณกำลังโต้เถียงกับข้อกำหนดภาษาและ MS MVP บางคนที่เขียนบล็อกในหัวข้อนี้ด้วยโดยให้การวัดผล ตรงกันข้ามกับคำแนะนำของคุณ ... ฉันเปิดใจรับข้อเสนอแนะว่าการวิจัยที่ฉันทำนั้นผิด แต่ฉันจะต้องอ่านรายการบล็อกของคุณเพื่อดูว่ามีอะไรบ้าง
try-catch
บล็อกเทียบกับtryparse()
วิธีการ แต่แนวคิดเหมือนกัน
ง่ายกว่าอย่างมากในการเขียนแก้ไขข้อบกพร่องและรักษาโค้ดที่ปราศจากข้อความแสดงข้อผิดพลาดของคอมไพเลอร์ข้อความเตือนการวิเคราะห์โค้ดและข้อยกเว้นที่ยอมรับตามปกติ (โดยเฉพาะข้อยกเว้นที่ถูกโยนทิ้งในที่เดียวและยอมรับในอีกที่หนึ่ง) เนื่องจากง่ายกว่าโดยเฉลี่ยแล้วโค้ดจะเขียนได้ดีขึ้นและมีข้อบกพร่องน้อยลง
สำหรับฉันแล้วโปรแกรมเมอร์และค่าใช้จ่ายด้านคุณภาพนั้นเป็นข้อโต้แย้งหลักในการใช้ try-catch สำหรับโฟลว์กระบวนการ
ค่าใช้จ่ายของข้อยกเว้นของคอมพิวเตอร์นั้นไม่มีนัยสำคัญเมื่อเปรียบเทียบและโดยปกติจะมีขนาดเล็กในแง่ของความสามารถของแอปพลิเคชันในการตอบสนองความต้องการด้านประสิทธิภาพในโลกแห่งความเป็นจริง
ฉันชอบบล็อกโพสต์ของ Hafthor มากและเพื่อเพิ่มสองเซ็นต์ของฉันในการสนทนานี้ฉันอยากจะบอกว่ามันเป็นเรื่องง่ายสำหรับฉันที่จะให้ DATA LAYER โยนข้อยกเว้นเพียงประเภทเดียว (DataAccessException) ด้วยวิธีนี้ BUSINESS LAYER ของฉันรู้ว่ามีข้อยกเว้นอะไรบ้างที่จะคาดหวังและจับมันได้ จากนั้นขึ้นอยู่กับกฎทางธุรกิจเพิ่มเติม (เช่นถ้าวัตถุทางธุรกิจของฉันมีส่วนร่วมในเวิร์กโฟลว์ ฯลฯ ) ฉันอาจโยนข้อยกเว้นใหม่ (BusinessObjectException) หรือดำเนินการต่อโดยไม่ต้องเปลี่ยน / โยน
บอกเลยว่าอย่าลังเลที่จะใช้ try..catch ทุกเมื่อที่จำเป็นและใช้อย่างชาญฉลาด!
ตัวอย่างเช่นวิธีนี้มีส่วนร่วมในเวิร์กโฟลว์ ...
ความคิดเห็น?
public bool DeleteGallery(int id)
{
try
{
using (var transaction = new DbTransactionManager())
{
try
{
transaction.BeginTransaction();
_galleryRepository.DeleteGallery(id, transaction);
_galleryRepository.DeletePictures(id, transaction);
FileManager.DeleteAll(id);
transaction.Commit();
}
catch (DataAccessException ex)
{
Logger.Log(ex);
transaction.Rollback();
throw new BusinessObjectException("Cannot delete gallery. Ensure business rules and try again.", ex);
}
}
}
catch (DbTransactionException ex)
{
Logger.Log(ex);
throw new BusinessObjectException("Cannot delete gallery.", ex);
}
return true;
}
เราสามารถอ่านได้ในภาษาโปรแกรม Pragmatics โดย Michael L. Scott ว่าคอมไพเลอร์ในปัจจุบันไม่ได้เพิ่มค่าใช้จ่ายใด ๆ ในกรณีทั่วไปซึ่งหมายความว่าเมื่อไม่มีข้อยกเว้นเกิดขึ้น ดังนั้นงานทุกชิ้นจึงเสร็จสิ้นในเวลารวบรวม แต่เมื่อมีข้อยกเว้นเกิดขึ้นในรันไทม์คอมไพเลอร์จำเป็นต้องทำการค้นหาไบนารีเพื่อค้นหาข้อยกเว้นที่ถูกต้องและสิ่งนี้จะเกิดขึ้นสำหรับการโยนใหม่ทุกครั้งที่คุณทำ
แต่ข้อยกเว้นเป็นข้อยกเว้นและค่าใช้จ่ายนี้เป็นที่ยอมรับอย่างสมบูรณ์ หากคุณพยายามดำเนินการจัดการข้อยกเว้นโดยไม่มีข้อยกเว้นและใช้รหัสข้อผิดพลาดในการส่งคืนแทนคุณอาจต้องมีคำสั่ง if สำหรับทุกรูทีนย่อยและสิ่งนี้จะเกิดขึ้นในค่าใช้จ่ายแบบเรียลไทม์จริงๆ คุณทราบว่าคำสั่ง if ถูกแปลงเป็นคำแนะนำในการประกอบบางส่วนซึ่งจะดำเนินการทุกครั้งที่คุณป้อนในรูทีนย่อยของคุณ
ขออภัยเกี่ยวกับภาษาอังกฤษของฉันหวังว่ามันจะช่วยคุณได้ ข้อมูลนี้อ้างอิงจากหนังสือที่อ้างถึงสำหรับข้อมูลเพิ่มเติมโปรดดูบทที่ 8.5 การจัดการข้อยกเว้น
ให้เราวิเคราะห์หนึ่งในต้นทุนที่ใหญ่ที่สุดที่เป็นไปได้ของบล็อก try / catch เมื่อใช้ในที่ที่ไม่จำเป็นต้องใช้:
int x;
try {
x = int.Parse("1234");
}
catch {
return;
}
// some more code here...
และนี่คือสิ่งที่ไม่ต้องลอง / จับ:
int x;
if (int.TryParse("1234", out x) == false) {
return;
}
// some more code here
หากไม่นับช่องว่างที่ไม่มีนัยสำคัญเราอาจสังเกตเห็นว่าโค้ดสองส่วนที่เท่ากันนี้มีความยาวเกือบเท่ากันทุกประการในหน่วยไบต์ หลังมีการเยื้องน้อยกว่า 4 ไบต์ เป็นสิ่งที่ไม่ดีหรือไม่?
เพื่อเพิ่มการดูถูกการบาดเจ็บนักเรียนตัดสินใจที่จะวนซ้ำในขณะที่อินพุตสามารถแยกวิเคราะห์เป็น int ได้ วิธีแก้ปัญหาโดยไม่ต้องลอง / จับอาจเป็นดังนี้:
while (int.TryParse(...))
{
...
}
แต่เมื่อใช้ try / catch นี้จะดูเป็นอย่างไร?
try {
for (;;)
{
x = int.Parse(...);
...
}
}
catch
{
...
}
บล็อก Try / catch เป็นวิธีที่วิเศษในการสูญเสียการเยื้องและเรายังไม่รู้ด้วยซ้ำว่าทำไมมันถึงล้มเหลว! ลองนึกภาพว่าผู้ที่ทำการดีบักรู้สึกอย่างไรเมื่อโค้ดยังคงดำเนินการผ่านข้อบกพร่องเชิงตรรกะที่ร้ายแรงแทนที่จะหยุดด้วยข้อผิดพลาดข้อยกเว้นที่ชัดเจน บล็อก Try / catch เป็นการตรวจสอบข้อมูล / สุขอนามัยของคนขี้เกียจ
ต้นทุนที่น้อยกว่าอย่างหนึ่งคือการบล็อก try / catch ปิดการใช้งานการเพิ่มประสิทธิภาพบางอย่าง: http://msmvps.com/blogs/peterritchie/archive/2007/06/22/performance-implications-of-try-catch-finally.aspx . ฉันเดาว่านั่นเป็นจุดบวกเช่นกัน สามารถใช้เพื่อปิดใช้งานการเพิ่มประสิทธิภาพที่อาจทำให้อัลกอริธึมการส่งข้อความที่ปลอดภัยและปลอดภัยสำหรับแอปพลิเคชันแบบมัลติเธรดและเพื่อตรวจจับสภาพการแข่งขันที่เป็นไปได้;) นั่นเป็นเพียงสถานการณ์เดียวที่ฉันคิดได้ว่าจะใช้ try / catch แม้จะมีทางเลือกอื่น
Int.Parse
Int.TryParse