ใน C # เหตุใดจึงมีการประกาศตัวแปรภายในบล็อกลองในขอบเขต


23

ฉันต้องการเพิ่มข้อผิดพลาดในการจัดการ:

var firstVariable = 1;
var secondVariable = firstVariable;

ด้านล่างจะไม่รวบรวม:

try
{
   var firstVariable = 1;
}
catch {}

try
{
   var secondVariable = firstVariable;
}
catch {}

เหตุใดจึงจำเป็นสำหรับ try catch block ที่จะส่งผลต่อขอบเขตของตัวแปรเช่นเดียวกับบล็อคโค้ดอื่น ๆ เห็นแก่ความสอดคล้องกันมันจะสมเหตุสมผลหรือไม่ที่เราจะสามารถห่อโค้ดของเราด้วยการจัดการข้อผิดพลาดโดยไม่จำเป็นต้อง refactor


14
A try.. catchคือรหัสบล็อกประเภทหนึ่งและตราบใดที่บล็อคโค้ดทั้งหมดไปคุณไม่สามารถประกาศตัวแปรหนึ่งและใช้ตัวแปรเดียวกันนั้นในอีกขอบเขตหนึ่งได้
Neil

"เป็นรหัสบล็อกประเภทหนึ่ง" โดยเฉพาะในทางใด ขอบคุณ
JᴀʏMᴇᴇ

7
ฉันหมายถึงอะไรระหว่างวงเล็บปีกกาคือบล็อคโค้ด คุณจะเห็นว่ามันตามหลังคำสั่ง if และทำตามคำสั่ง for แม้ว่าแนวคิดจะเหมือนกัน เนื้อหาอยู่ในขอบเขตที่ยกระดับตามขอบเขตของพาเรนต์ ฉันค่อนข้างมั่นใจว่านี่จะเป็นปัญหาได้ถ้าคุณใช้วงเล็บปีกกา{}โดยไม่ลอง
Neil

เคล็ดลับ: โปรดทราบว่าการใช้ (IDisposable) {} และเพียง {} ก็มีผลเช่นเดียวกัน เมื่อคุณใช้การใช้กับ IDisposable มันจะทำความสะอาดทรัพยากรโดยอัตโนมัติโดยไม่คำนึงถึงความสำเร็จหรือความล้มเหลว มีข้อยกเว้นบางอย่างไม่ได้อยู่ที่นี้ทุกชั้นที่คุณคาดหวังใช้ IDisposable ...
จูเลีย McGuigan

1
การอภิปรายจำนวนมากเกี่ยวกับคำถามเดียวกันนี้ใน StackOverflow ที่นี่: stackoverflow.com/questions/94977/…
Jon Schneider

คำตอบ:


90

เกิดอะไรขึ้นถ้ารหัสของคุณคือ:

try
{
   MethodThatMightThrow();
   var firstVariable = 1;
}
catch {}

try
{
   var secondVariable = firstVariable;
}
catch {}

ตอนนี้คุณกำลังพยายามใช้ตัวแปรที่ไม่ได้ประกาศ ( firstVariable) หากการเรียกใช้เมธอดของคุณส่งผล

หมายเหตุ : ตัวอย่างด้านบนตอบคำถามดั้งเดิมโดยเฉพาะซึ่งระบุว่า "เห็นแก่ความสอดคล้อง - กัน" สิ่งนี้แสดงให้เห็นว่ามีเหตุผลอื่นนอกเหนือจากความสอดคล้อง แต่ตามคำตอบของปีเตอร์แสดงให้เห็นว่ายังมีข้อโต้แย้งที่มีประสิทธิภาพจากความมั่นคงซึ่งแน่นอนว่าเป็นปัจจัยสำคัญในการตัดสินใจ


Ahh นี่คือสิ่งที่ฉันเป็นหลังจากนั้น ฉันรู้ว่ามีฟีเจอร์ภาษาบางอย่างที่ทำให้สิ่งที่ฉันแนะนำเป็นไปไม่ได้ แต่ฉันไม่สามารถคิดอะไรได้ ขอบคุณมาก ๆ.
JᴀʏMᴇᴇ

1
"ตอนนี้คุณกำลังพยายามใช้ตัวแปรที่ไม่ได้ประกาศหากการเรียกใช้เมธอดของคุณ" นอกจากนี้สมมติว่าสิ่งนี้หลีกเลี่ยงได้โดยการรักษาตัวแปรราวกับว่ามันถูกประกาศ แต่ไม่ได้เริ่มต้นก่อนรหัสที่อาจโยน จากนั้นมันจะไม่ถูกยกเลิกการประกาศ แต่ก็ยังอาจไม่ได้รับมอบหมายและการวิเคราะห์การมอบหมายที่ชัดเจนจะห้ามการอ่านค่าของมัน (โดยไม่มีการมอบหมายที่แทรกแซงได้
Eliah Kagan

3
สำหรับภาษาแบบคงที่เช่น C # การประกาศนั้นเกี่ยวข้องกับการรวบรวมเท่านั้น คอมไพเลอร์สามารถย้ายการประกาศก่อนหน้านี้ในขอบเขตได้อย่างง่ายดาย ความจริงที่สำคัญกว่าของรันไทม์คือตัวแปรอาจไม่สามารถกำหนดค่าเริ่มต้นได้
jpmc26

3
ฉันไม่เห็นด้วยกับคำตอบนี้ C # มีกฎที่ไม่สามารถอ่านตัวแปรที่ไม่ได้กำหนดค่าเริ่มต้นได้พร้อมกับการรับรู้ข้อมูลบางส่วน (ลองประกาศตัวแปรในกรณีของ a switchและเข้าถึงตัวแปรอื่น ๆ ) กฎนี้สามารถนำไปใช้ที่นี่ได้อย่างง่ายดายและป้องกันไม่ให้โค้ดนี้รวบรวมได้ ฉันคิดว่าคำตอบของปีเตอร์ด้านล่างมีเหตุผลมากขึ้น
เซบาสเตียนเรดล

2
มีความแตกต่างระหว่าง undecared uninitialized และ C # ติดตามพวกเขาแยกกัน หากคุณได้รับอนุญาตให้ใช้ตัวแปรนอกบล็อกที่มีการประกาศก็หมายความว่าคุณจะสามารถกำหนดให้กับมันในcatchบล็อกแรกแล้วมันจะถูกกำหนดอย่างแน่นอนในtryบล็อกที่สอง
svick

64

ฉันรู้ว่านี่เป็นคำตอบที่ดีจากเบ็น แต่ฉันต้องการพูดถึงความมั่นคงที่ถูกผลักออกไปอย่างสะดวก สมมติว่าtry/catchบล็อกนั้นไม่มีผลกับขอบเขตคุณจะต้อง:

{
    // new scope here
}

try
{
   // Not new scope
}

และสำหรับฉันการชนนี้มุ่งไปที่หลักการแห่งความประหลาดใจน้อยที่สุด (POLA)เพราะตอนนี้คุณมี{และ}ทำหน้าที่สองอย่างขึ้นอยู่กับบริบทของสิ่งที่นำหน้าพวกเขา

วิธีเดียวของระเบียบนี้คือการกำหนดเครื่องหมายอื่น ๆ เพื่อแยกtry/catchบล็อก ซึ่งเริ่มเพิ่มกลิ่นรหัส ดังนั้นเมื่อถึงเวลาที่คุณไม่มีtry/catchภาษาในตัวมันจะเป็นเรื่องยุ่งเหยิงที่คุณจะทำได้ดีกว่ากับเวอร์ชั่นที่ จำกัด ขอบเขต


อีกคำตอบที่ยอดเยี่ยม และฉันไม่เคยได้ยิน POLA เลยอ่านเพิ่มเติมได้ดีมาก ขอบคุณมากเพื่อน
JᴀʏMᴇᴇ

วิธีเดียวที่จะทำให้เป็นระเบียบนี้คือการกำหนดเครื่องหมายอื่น ๆ เพื่อแยกtry/ catchบล็อก " - คุณหมายถึง: try { { // scope } }? :)
CompuChip

@CompuChip ที่จะ{}ดึงหน้าที่สองเท่ามาเป็นขอบเขตและไม่สร้างขอบเขตขึ้นอยู่กับบริบทที่ยังคงอยู่ try^ //no-scope ^จะเป็นตัวอย่างของเครื่องหมายที่แตกต่างกัน
Leliel

1
ในความคิดของฉันนี่เป็นเหตุผลพื้นฐานมากและใกล้กับคำตอบ "ของจริง"
Jack Aidley

@JackAidley โดยเฉพาะอย่างยิ่งเนื่องจากคุณสามารถเขียนโค้ดที่คุณใช้ตัวแปรที่อาจไม่ได้รับมอบหมาย ดังนั้นในขณะที่คำตอบของเบ็นมีประเด็นเกี่ยวกับพฤติกรรมที่เป็นประโยชน์นี้ฉันไม่เห็นว่าทำไมพฤติกรรมจึงมีอยู่ คำตอบของเบ็นไม่ได้สังเกต OP ที่พูดว่า "เห็นแก่ความมั่นคง" แต่ความมั่นคงนั้นเป็นเหตุผลที่สมบูรณ์แบบ! ขอบเขตแคบมีประโยชน์อื่น ๆ ทุกประเภท
Kat

21

เห็นแก่ความสอดคล้องกันมันจะสมเหตุสมผลหรือไม่ที่เราจะสามารถห่อโค้ดของเราด้วยการจัดการข้อผิดพลาดโดยไม่จำเป็นต้อง refactor

เพื่อที่จะตอบนี้ก็จำเป็นต้องดูที่มากกว่าเพียงแค่ขอบเขตของตัวแปร

แม้ว่าตัวแปรยังคงอยู่ในขอบเขตก็จะไม่ได้รับการมอบหมายแน่นอน

การประกาศตัวแปรใน try block เป็นการแสดงออกถึงคอมไพเลอร์และต่อผู้อ่านมนุษย์ว่ามันมีความหมายเฉพาะในบล็อกนั้น มันมีประโยชน์สำหรับคอมไพเลอร์ในการบังคับใช้

หากคุณต้องการให้ตัวแปรอยู่ในขอบเขตหลังจากลองบล็อกคุณสามารถประกาศตัวแปรภายนอกบล็อก:

var zerothVariable = 1_000_000_000_000L;
int firstVariable;

try {
    // Change checked to unchecked to allow the overflow without throwing.
    firstVariable = checked((int)zerothVariable);
}
catch (OverflowException e) {
    Console.Error.WriteLine(e.Message);
    Environment.Exit(1);
}

นั่นเป็นการแสดงออกว่าตัวแปรอาจมีความหมายนอกบล็อกการลอง คอมไพเลอร์จะอนุญาตสิ่งนี้

แต่มันก็แสดงให้เห็นเหตุผลอื่นที่มักจะไม่เป็นประโยชน์ในการรักษาตัวแปรในขอบเขตหลังจากแนะนำพวกเขาในลองบล็อก คอมไพเลอร์ C # ดำเนินการวิเคราะห์การกำหนดที่แน่นอนและห้ามมิให้อ่านค่าของตัวแปรที่ไม่ได้พิสูจน์ว่าได้รับค่าแล้ว ดังนั้นคุณยังไม่สามารถอ่านจากตัวแปรได้

สมมติว่าฉันพยายามอ่านจากตัวแปรหลังจากลองบล็อก:

Console.WriteLine(firstVariable);

นั่นจะทำให้เกิดข้อผิดพลาดในการคอมไพล์เวลา :

CS0165 การใช้ตัวแปรท้องถิ่นที่ไม่ได้กำหนด 'firstVariable'

ฉันเรียกว่าEnvironment.Exitใน catch block ดังนั้นฉันรู้ว่าตัวแปรได้รับการกำหนดก่อนการเรียกไปยัง Console.WriteLine แต่คอมไพเลอร์ไม่ได้อนุมานเรื่องนี้

ทำไมผู้แปลถึงเข้มงวดมาก?

ฉันไม่สามารถทำสิ่งนี้ได้:

int n;

try {
    n = 10; // I know this won't throw an IOException.
}
catch (IOException) {
}

Console.WriteLine(n);

วิธีหนึ่งในการดูข้อ จำกัด นี้คือการวิเคราะห์การกำหนดที่ชัดเจนใน C # นั้นไม่ซับซ้อนมากนัก แต่อีกวิธีหนึ่งในการดูมันคือเมื่อคุณเขียนโค้ดในบล็อกลองด้วยคำสั่ง catch คุณกำลังบอกทั้งคอมไพเลอร์และผู้อ่านคนใด ๆ ว่าควรได้รับการปฏิบัติเหมือนไม่สามารถรันได้ทั้งหมด

เพื่อแสดงให้เห็นว่าสิ่งที่ผมหมายถึงคิดว่าคอมไพเลอร์ที่ได้รับอนุญาตโค้ดข้างต้น แต่แล้วคุณเพิ่มการโทรในบล็อกลองให้ฟังก์ชั่นที่คุณเองรู้ว่าจะไม่โยนข้อยกเว้น ไม่สามารถรับประกันได้ว่าฟังก์ชั่นที่เรียกใช้ไม่ได้โยนIOExceptionคอมไพเลอร์ไม่สามารถรู้ได้ว่าnได้รับมอบหมายจากนั้นคุณจะต้องปรับโครงสร้างใหม่

นี่คือการกล่าวโดยการวิเคราะห์ขั้นสูงในการพิจารณาว่าตัวแปรที่กำหนดในการลองบล็อกด้วย catch clauses ได้รับการกำหนดแน่นอนในภายหลังผู้แปลคอมไพเลอร์ช่วยให้คุณหลีกเลี่ยงการเขียนโค้ดที่มีแนวโน้มที่จะทำลายในภายหลัง (ท้ายที่สุดการจับข้อยกเว้นมักจะหมายความว่าคุณคิดว่าอาจถูกโยนทิ้ง)

คุณสามารถตรวจสอบให้แน่ใจว่าตัวแปรถูกกำหนดผ่านเส้นทางโค้ดทั้งหมด

คุณสามารถสร้างโค้ดคอมไพล์โดยให้ค่าตัวแปรก่อนหน้าบล็อกลองหรือใน catch block ด้วยวิธีนี้มันจะยังคงได้รับการเริ่มต้นหรือกำหนดแม้ว่าการมอบหมายในบล็อกลองไม่เกิดขึ้น ตัวอย่างเช่น:

var n = 0; // But is this meaningful, or just covering a bug?

try {
    n = 10;
}
catch (IOException) {
}

Console.WriteLine(n);

หรือ:

int n;

try {
    n = 10;
}
catch (IOException) {
    n = 0; // But is this meaningful, or just covering a bug?
}

Console.WriteLine(n);

รวบรวมเหล่านั้น แต่เป็นการดีที่สุดที่จะทำอะไรแบบนั้นถ้าค่าเริ่มต้นที่คุณให้มันสมเหตุสมผล*และสร้างพฤติกรรมที่ถูกต้อง

โปรดทราบว่าในกรณีที่สองนี้ที่คุณกำหนดตัวแปรในลองบล็อกและบล็อก catch ทั้งหมดแม้ว่าคุณสามารถอ่านตัวแปรหลังจากลอง catch คุณยังคงไม่สามารถอ่านตัวแปรภายในfinallyบล็อกที่แนบเนื่องจากการดำเนินการสามารถออกจากบล็อกลองในสถานการณ์เกินกว่าที่เรามักจะคิดเกี่ยวกับ

* อย่างไรก็ตามบางภาษาเช่น C และ C ++ ทั้งคู่อนุญาตตัวแปรที่ไม่มีการกำหนดค่าเริ่มต้นและไม่มีการวิเคราะห์การกำหนดที่แน่นอนเพื่อป้องกันการอ่านจากพวกเขา เนื่องจากการอ่านหน่วยความจำที่ไม่ได้กำหนดค่าเริ่มต้นทำให้โปรแกรมทำงานในลักษณะnondeterministic และไม่อยู่กับร่องกับรอยจึงแนะนำให้หลีกเลี่ยงการแนะนำตัวแปรในภาษาเหล่านั้นโดยไม่ต้องใช้ initializer ในภาษาที่มีการวิเคราะห์การมอบหมายที่ชัดเจนเช่น C # และ Java คอมไพเลอร์ช่วยให้คุณประหยัดจากการอ่านตัวแปรที่ไม่ได้กำหนดค่าเริ่มต้นและจากความชั่วที่น้อยกว่าในการเริ่มต้นพวกเขาด้วยค่าที่ไม่มีความหมาย

คุณสามารถทำให้มันเป็นเส้นทางรหัสที่ตัวแปรไม่ได้รับมอบหมายโยนข้อยกเว้น (หรือกลับ)

หากคุณวางแผนที่จะดำเนินการบางอย่าง (เช่นการบันทึก) และสร้างข้อยกเว้นอีกครั้งหรือโยนข้อยกเว้นอื่นและสิ่งนี้จะเกิดขึ้นในส่วนคำสั่ง catch ใด ๆ ที่ไม่ได้กำหนดตัวแปรไว้คอมไพเลอร์จะทราบว่ามีการกำหนดตัวแปรแล้ว:

int n;

try {
    n = 10;
}
catch (IOException e) {
    Console.Error.WriteLine(e.Message);
    throw;
}

Console.WriteLine(n);

การรวบรวมนั้นและอาจเป็นทางเลือกที่สมเหตุสมผล อย่างไรก็ตามในการประยุกต์ใช้จริงเว้นแต่ข้อยกเว้นจะโยนเฉพาะในสถานการณ์ที่มันไม่ได้ทำให้ความรู้สึกที่จะพยายามกู้คืน*คุณควรตรวจสอบให้แน่ใจว่าคุณจะยังคงจับและถูกต้องจัดการกับมันอยู่ที่ไหนสักแห่ง

(คุณไม่สามารถอ่านตัวแปรในช่วงท้ายบล็อกในสถานการณ์นี้ได้เช่นกัน แต่ก็ไม่รู้สึกว่าคุณควรจะสามารถ - หลังจากทั้งหมดบล็อกสุดท้ายจะทำงานเป็นหลักเสมอและในกรณีนี้ตัวแปรจะไม่ได้รับมอบหมายเสมอไป .)

* ตัวอย่างเช่นแอปพลิเคชันจำนวนมากไม่มี catch clause ที่จัดการOutOfMemoryExceptionเนื่องจากสิ่งที่พวกเขาสามารถทำได้เกี่ยวกับมันอาจเป็นอย่างน้อยก็แย่ไม่แพ้กัน

บางทีคุณจริงๆไม่ต้องการที่จะ refactor รหัส

ในตัวอย่างของคุณคุณแนะนำfirstVariableและsecondVariableลองบล็อก ดังที่ฉันได้กล่าวไว้คุณสามารถกำหนดพวกเขาก่อนที่จะลองบล็อกที่พวกเขาได้รับมอบหมายดังนั้นพวกเขาจะยังคงอยู่ในขอบเขตหลังจากนั้นและคุณสามารถตอบสนอง / หลอกลวงคอมไพเลอร์ในการอนุญาตให้คุณอ่านจากพวกเขา

แต่รหัสที่ปรากฏหลังจากบล็อกเหล่านั้นน่าจะขึ้นอยู่กับพวกเขาได้รับมอบหมายอย่างถูกต้อง หากเป็นกรณีนี้รหัสของคุณควรสะท้อนและตรวจสอบให้แน่ใจ

ก่อนอื่นคุณสามารถจัดการกับข้อผิดพลาดที่นั่นได้หรือไม่ หนึ่งในสาเหตุของการจัดการข้อยกเว้นคือเพื่อให้ง่ายต่อการจัดการข้อผิดพลาดที่พวกเขาสามารถจัดการได้อย่างมีประสิทธิภาพแม้ว่าจะไม่ได้อยู่ใกล้ที่ที่พวกเขาเกิดขึ้น

หากคุณไม่สามารถจัดการกับข้อผิดพลาดในฟังก์ชั่นที่เริ่มต้นและใช้ตัวแปรเหล่านั้นได้บางทีบล็อกลองไม่ควรอยู่ในฟังก์ชันนั้นเลย แต่แทนที่จะอยู่ที่อื่นที่สูงกว่า (เช่นในรหัสที่เรียกใช้ฟังก์ชันนั้นหรือรหัส ที่เรียกรหัสนั้น ) เพียงให้แน่ใจว่าคุณไม่ได้ตั้งใจจับยกเว้นโยนที่อื่นและผิดสมมติว่ามันถูกโยนลงในขณะที่การเริ่มต้นและfirstVariablesecondVariable

อีกวิธีคือใส่รหัสที่ใช้ตัวแปรในบล็อกลอง สิ่งนี้มักจะสมเหตุสมผล อีกครั้งหากข้อยกเว้นเดียวกันกับที่คุณจับได้จาก initializers อาจถูกโยนจากรหัสที่อยู่รอบ ๆ คุณควรตรวจสอบให้แน่ใจว่าคุณไม่ละเลยความเป็นไปได้นั้นเมื่อจัดการกับมัน

(ฉันสมมติว่าคุณกำลังเริ่มต้นตัวแปรด้วยนิพจน์ที่ซับซ้อนกว่าที่แสดงในตัวอย่างของคุณเช่นพวกเขาสามารถโยนข้อยกเว้นได้จริงและคุณยังไม่ได้วางแผนที่จะจับข้อยกเว้นที่เป็นไปได้ทั้งหมดแต่เพียงจับข้อยกเว้นเฉพาะใด ๆคุณสามารถคาดหวังและจัดการอย่างมีความหมายมันเป็นความจริงที่โลกแห่งความจริงไม่ได้ดีนักและบางครั้งรหัสการผลิตก็ทำเช่นนี้แต่เนื่องจากเป้าหมายของคุณที่นี่คือการจัดการข้อผิดพลาดที่เกิดขึ้นในขณะเริ่มต้นตัวแปรเฉพาะสองประการ จุดประสงค์ควรเฉพาะเจาะจงกับข้อผิดพลาดใด ๆ ที่เกิดขึ้น)

วิธีที่สามคือการแยกรหัสที่สามารถล้มเหลวและลองจับที่จัดการมันเป็นวิธีการของตัวเอง สิ่งนี้มีประโยชน์หากคุณอาจต้องการจัดการกับข้อผิดพลาดอย่างสมบูรณ์ก่อนจากนั้นไม่ต้องกังวลกับการจับข้อยกเว้นโดยไม่ตั้งใจซึ่งควรจัดการที่อื่นแทน

ตัวอย่างเช่นสมมติว่าคุณต้องการออกจากแอปพลิเคชันทันทีเมื่อไม่สามารถกำหนดตัวแปรได้ (เห็นได้ชัดว่าไม่ใช่การจัดการข้อยกเว้นทั้งหมดสำหรับข้อผิดพลาดร้ายแรงนี่เป็นเพียงตัวอย่างและอาจใช่หรือไม่ใช่วิธีที่คุณต้องการให้แอปพลิเคชันของคุณตอบสนองต่อปัญหา) คุณสามารถทำสิ่งนี้:

// In real life, this should be named more descriptively.
private static (int firstValue, int secondValue) GetFirstAndSecondValues()
{
    try {
        // This code is contrived. The idea here is that obtaining the values
        // could actually fail, and throw a SomeSpecificException.
        var firstVariable = 1;
        var secondVariable = firstVariable;
        return (firstVariable, secondVariable);
    }
    catch (SomeSpecificException e) {
        Console.Error.WriteLine(e.Message);
        Environment.Exit(1);
        throw new InvalidOperationException(); // unreachable
    }
}

// ...and of course so should this.
internal static void MethodThatUsesTheValues()
{
    var (firstVariable, secondVariable) = GetFirstAndSecondValues();

    // Code that does something with them...
}

รหัสนั้นจะคืนค่าและแยกโครงสร้าง ValueTuple ด้วยไวยากรณ์ของ C # 7.0เพื่อคืนค่าหลายค่า แต่ถ้าคุณยังคงใช้ C # รุ่นก่อนหน้าคุณยังคงสามารถใช้เทคนิคนี้ได้ ตัวอย่างเช่นคุณสามารถใช้พารามิเตอร์หรือกลับวัตถุที่กำหนดเองที่ให้ทั้งสองค่า นอกจากนี้หากตัวแปรสองตัวนั้นไม่ได้เกี่ยวข้องกันอย่างแน่นหนาน่าจะมีวิธีแยกกันสองวิธี

โดยเฉพาะอย่างยิ่งหากคุณมีหลายวิธีเช่นนั้นคุณควรพิจารณาการรวมรหัสของคุณไว้ที่ส่วนกลางเพื่อแจ้งให้ผู้ใช้ทราบถึงข้อผิดพลาดร้ายแรงและการเลิกใช้ (ตัวอย่างเช่นคุณสามารถเขียนDieวิธีการที่มีmessageพารามิเตอร์.) บรรทัดจะไม่ดำเนินการจริงเพื่อให้คุณไม่จำเป็น (และไม่ควร) เขียนประโยคจับมันthrow new InvalidOperationException();

นอกเหนือจากการเลิกสูบบุหรี่เมื่อข้อผิดพลาดเกิดขึ้นโดยเฉพาะอย่างยิ่งคุณอาจรหัสบางครั้งการเขียนที่มีลักษณะเช่นนี้ถ้าคุณโยนข้อยกเว้นชนิดอื่นที่ wraps ยกเว้นเดิม (ในสถานการณ์นั้นคุณไม่จำเป็นต้องใช้นิพจน์การขว้างปาที่สองและไม่สามารถเข้าถึงได้)

สรุป: ขอบเขตเป็นเพียงส่วนหนึ่งของภาพ

คุณสามารถบรรลุผลของการห่อรหัสของคุณด้วยการจัดการข้อผิดพลาดโดยไม่ต้อง refactoring (หรือถ้าคุณต้องการด้วยแทบ refactoring ใด ๆ ) เพียงแค่แยกการประกาศของตัวแปรจากการกำหนดของพวกเขา คอมไพเลอร์อนุญาตให้ทำได้หากคุณปฏิบัติตามกฎการกำหนดที่ชัดเจนของ C # และประกาศตัวแปรล่วงหน้าของบล็อก try ทำให้ขอบเขตใหญ่ขึ้น แต่การปรับโครงสร้างอีกครั้งอาจเป็นตัวเลือกที่ดีที่สุดของคุณ


"เมื่อคุณเขียนโค้ดในบล็อกลองกับคำสั่ง catch คุณกำลังบอกทั้งคอมไพเลอร์และผู้อ่านคนใด ๆ ว่าควรได้รับการปฏิบัติเหมือนว่ามันอาจจะไม่สามารถทำงานได้ทั้งหมด" สิ่งที่คอมไพเลอร์ใส่ใจคือการควบคุมนั้นสามารถเข้าถึงคำสั่งในภายหลังแม้ว่าข้อความก่อนหน้านี้จะมีข้อยกเว้น คอมไพเลอร์โดยปกติจะสมมติว่าหากคำสั่งหนึ่งมีข้อยกเว้นข้อยกเว้นคำสั่งถัดไปจะไม่ถูกดำเนินการดังนั้นตัวแปรที่ไม่ได้กำหนดจะไม่ถูกอ่าน การเพิ่ม 'catch' จะช่วยให้การควบคุมสามารถเข้าถึงคำสั่งในภายหลัง - มันเป็น catch ที่สำคัญไม่ใช่รหัสในบล็อก try
Pete Kirkham
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.