จงใจยกข้อยกเว้นเพื่อใช้ catch


10

สำหรับแบบทั่วไปที่if...elseมีการจัดการข้อยกเว้นบางอย่างเช่นตัวอย่างต่อไปนี้เป็นแนวทางปฏิบัติที่แนะนำเพื่อหลีกเลี่ยงการทำสำเนารหัสหรือไม่

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

แทน...

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        return null;
    }
}
catch(Exception ex)
{
    return null;
}

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


หากวิธีการมีขนาดเล็กพอฉันจะลบสิ่งอื่นและคืนค่า Null นอกบล็อก trycatch ดังนั้นฉันต้องคืนค่า Null เพียงครั้งเดียว
Fabio Marcolini

คำตอบ:


12

Microsoft ไม่สนับสนุนการใช้การจัดการข้อยกเว้นสำหรับการควบคุมการไหล

และโต๊ะกลมในหัวข้อที่มีอยู่

อย่างที่กล่าวไว้ C # สนับสนุนการทำเช่นนั้นและฉันคิดว่ามันขึ้นอยู่กับเงื่อนไขที่พบว่าข้อยกเว้นเป็นการตอบสนองที่เหมาะสมที่สุด


1
มันทำให้ฉันรู้สึกว่าเรื่องแบบนี้เป็นเพียงการพยายามอย่างหนักที่จะไม่ใช้เหตุการณ์
Radarbob

@radarbob: เหตุการณ์เกี่ยวข้องกับเรื่องนี้อย่างไร

@grovesNL - โยนข้อยกเว้นที่จุดเฉพาะเพื่อเรียกวิธีการบางอย่างใน catch block หรือไม่ Quacks ชอบจัดกิจกรรมให้ฉัน
Radarbob

@radarbob: มันไม่ใช่เหตุการณ์ มีกรณีการใช้งานตัวอย่างจำนวนมากที่จะใช้ตามที่กล่าวไว้ในลิงก์โต๊ะกลมของคำตอบ

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

6

การเข้าชมผลการปฏิบัติงานนั้นอาจเล็กน้อยมากดังที่อธิบายไว้ในคำตอบนี้นี้

ดังนั้นไปกับแนวคิดที่ว่าประสิทธิภาพไม่เป็นปัญหา คุณกำลังขว้างปาSystem.Exception, เพียงเพื่อให้การดำเนินการย้ายเข้าไปในcatchข้อ การขว้าง a BadControlFlowThatShouldBeRewrittenExceptionอาจจะเกินความจริงไปหน่อย

มาทำลายมันกันเถอะ เรามี:

  • วิธีการGetDataFromServer(ชื่อวิธีควรจะ PascalCase ใน C #) boolซึ่งอาจจะสามารถโยนยกเว้นหรือผลตอบแทน
  • หากผลเป็นวิ่งtrueProcessData
  • กลับไปเป็นnullอย่างอื่น

ดูเหมือนว่าวิธีการที่เขียนโค้ดนี้กำลังทำสิ่งต่าง ๆ มากเกินไป GetDataFromServerกลับboolดูเหมือนว่าข้อบกพร่องการออกแบบผมจะคาดหวังว่าวิธีการที่จะส่งข้อมูลที่ได้รับจากเซิร์ฟเวอร์บางIEnumerable<SomeType>ที่จะมี 0 รายการขึ้นไป - คือผลตอบแทนที่เส้นทางความสุขnรายการที่n> 0 , ไม่ให้มีความสุข เส้นทางส่งคืนสินค้า 0 รายการและเส้นทางที่ไม่มีความสุขจะระเบิดด้วยข้อยกเว้นที่ไม่สามารถจัดการได้ไม่ว่าจะเป็นอะไรก็ตาม

นั่นเปลี่ยนวิธีการที่ดูเหมือนมาก - อีกครั้งมันยากที่จะบอกว่าเรื่องนี้สมเหตุสมผลหรือไม่เนื่องจากโพสต์ดั้งเดิมมีจุดทางออกเพียงจุดเดียวเท่านั้น (และจะไม่คอมไพล์เนื่องจากเส้นทางโค้ดทั้งหมดจะคืนค่า ) นี่เป็นเพียงการคาดเดาป่า:

try
{
    var result = GetDataFromServer();
    return ProcessData(result);
}
catch
{
    return null;
}

ที่นี่คุณจะดูProcessDataและเห็นว่ามันซ้ำแล้วซ้ำresultอีกและส่งคืนnullหากไม่มีรายการในIEnumerableถ้ามีรายการที่ไม่มีใน

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

ด้วยcatchประโยคทั่วไปที่ไม่ได้รับการยกเว้นมันค่อนข้างยากที่จะวินิจฉัยอะไร ฉันจะทำอย่างน้อยที่สุดแทน:

catch(Exception e)
{
    return null;
}

อย่างน้อยคุณก็สามารถทำลายและตรวจสอบeว่ามีอะไรผิดปกติหรือไม่


TL : DR : ไม่การขว้างและจับข้อยกเว้นสำหรับการควบคุมการไหลไม่ใช่ความคิดที่ดี


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

3
เสียงเช่นนี้น่าจะเป็นคำถามสำหรับโปรแกรมเมอร์แล้ว เราตรวจสอบโค้ดไม่ใช่แนวคิด
มาลาคี

2

ในคำตอบแรกของคุณมีการแสดงที่ไม่จำเป็นต้องมี

try
{
    if (GetDataFromServer())
    {
        return ProcessData();
    }
    else
    {
        throw new Exception();
    }
catch(Exception ex)
{
    return null;
}

เมื่อคุณออกจากคำสั่ง if เพื่อเข้าสู่คำสั่ง Catch เมื่อคุณไม่จำเป็นต้องเปลี่ยนทิศทางของรหัสดังนั้นต้องพูด

ถ้าคุณต้องการที่จะreturn null; ทำมันในคำสั่งอื่นไม่ได้อยู่ในการจับที่ถูกจับหลังจากถูกโยนออกมาจากคำสั่งอื่น

อาจไม่ได้ใช้กับรหัสจริงของคุณแต่สำหรับรหัสทั่วไปที่คุณให้ไว้จะมีผลบังคับใช้

มาตรฐานบอกว่าคุณไม่ควรทำเช่นนี้

มาตรฐานบอกว่าคุณควรทำเช่นนี้ (อีกครั้งตามรหัสทั่วไปที่ให้ไว้ใน OP)

if (GetDataFromServer())
{
    return ProcessData();
}
else
{
    Return null
}

และเนื่องจากคุณไม่มีข้อยกเว้นเฉพาะใด ๆ ที่คุณกำลังจับคุณไม่ควรลองจับที่นี่

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


1

ทำไมไม่ง่ายกว่า:

if (!GetDataFromServer()) return null;
ProcessData();

หากตัวจัดการข้อยกเว้นกำลังจะเกิดขึ้นควรอยู่ใน ProcessData ()


ทำไมฉันไม่ต้องการส่งข้อยกเว้นProcessData()ไปที่ระดับสูงสุด?
grovesNL

@grovesNL ไม่มีอะไรที่เป็นประโยชน์กับการทำข้อยกเว้นที่นี่
Loren Pechtel

1
งั้นเหรอ หากProcessData()มีข้อผิดพลาดเกิดขึ้นตอนนี้จะไม่ได้รับการจัดการ ฉันต้องการให้return nullอยู่ในระดับนี้หากProcessData()มีข้อผิดพลาดโดยไม่แก้ไขProcessData()ตัวเอง
grovesNL
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.