แนวทางปฏิบัติที่ดีที่สุดสำหรับ if / return


60

ฉันต้องการที่จะรู้ว่าสิ่งที่ถือว่าเป็นวิธีที่ดีกว่าของการกลับมาเมื่อฉันมีifคำสั่ง

ตัวอย่างที่ 1:

public bool MyFunction()
{
   // Get some string for this example
   string myString = GetString();

   if (myString == null)
   {
      return false;
   }
   else
   {
      myString = "Name " + myString;
      // Do something more here...
      return true;
   }
}

ตัวอย่างที่ 2:

public bool MyFunction()
{
   // Get some string for this example
   string myString = GetString();

   if (myString == null)
   {
      return false;
   }

   myString = "Name " + myString;
   // Do something more here...
   return true;
}

อย่างที่คุณเห็นในตัวอย่างฟังก์ชั่นทั้งสองจะกลับมาtrue/falseแต่มันเป็นความคิดที่ดีที่จะใส่elseคำสั่งเหมือนในตัวอย่างแรกหรือดีกว่าที่จะไม่ใส่มัน?


7
หากคุณกำลังตรวจสอบข้อผิดพลาดเฉพาะใน 'if' แรกคุณควรไม่รวม 'else' ไว้ก่อนเพราะข้อผิดพลาดไม่ควรถือเป็นส่วนหนึ่งของตรรกะที่แท้จริง
Mert Akcakaya

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


14
ให้ฉันรุ่นแรกเป็นเหมือนไล่นักเรียนทุกคนในห้องที่ไม่ได้เสร็จสิ้นการบ้านของพวกเขาและจากนั้นเมื่อพวกเขาจะหายไปพูดกับส่วนที่เหลือของนักเรียน "ตอนนี้ถ้าคุณได้เสร็จสิ้นการบ้านของคุณ ..." มันสมเหตุสมผล แต่ไม่จำเป็น elseเนื่องจากเงื่อนไขไม่ได้จริงๆมีเงื่อนไขอีกต่อไปผมมักจะวาง
Nicole

1
'ทำอะไรเพิ่มเติมที่นี่' ที่คุณต้องการทำคืออะไร นั่นอาจเปลี่ยนแปลงวิธีการออกแบบฟังก์ชั่นของคุณได้อย่างสมบูรณ์
เบเนดิกต์

คำตอบ:


81

ตัวอย่างที่ 2 เรียกว่า block Guard เหมาะกว่าที่จะส่งคืน / ส่งข้อยกเว้นก่อนเวลาหากมีสิ่งผิดปกติ (พารามิเตอร์ไม่ถูกต้องหรือสถานะไม่ถูกต้อง) ในการไหลของลอจิกปกติจะดีกว่าที่จะใช้ตัวอย่างที่ 1


+1 - ความแตกต่างที่ดีและสิ่งที่ฉันจะตอบ
Telastyn

3
@ pR0Ps มีคำตอบเดียวกันด้านล่างและให้ตัวอย่างรหัสว่าทำไมมันถึงกลายเป็นเส้นทางที่สะอาดกว่าที่จะติดตาม +1 สำหรับคำตอบที่ดี

คำถามนี้ถูกถามหลายครั้งใน SO และถึงแม้ว่ามันอาจจะเป็นที่ถกเถียงกันนี่เป็นคำตอบที่ดี หลายคนที่ได้รับการฝึกฝนให้กลับมาจากจุดสิ้นสุดมีปัญหากับแนวคิดนี้
Bill K

2
+1 การหลีกเลี่ยงบล็อกป้องกันอย่างไม่เหมาะสมมีแนวโน้มที่จะก่อให้เกิดรหัสลูกศร
Brian

ตัวอย่างทั้งสองไม่แสดงบล็อกป้องกันใช่หรือไม่
ernie

44

สไตล์ส่วนตัวของฉันคือการใช้ซิงเกิ้ลifสำหรับบล็อกป้องกันและif/ elseในรหัสการประมวลผลวิธีการจริง

ในกรณีนี้คุณกำลังใช้myString == nullเป็นเงื่อนไขการป้องกันดังนั้นฉันมักจะใช้ifรูปแบบเดียว

พิจารณาโค้ดที่ซับซ้อนกว่านี้เล็กน้อย:

ตัวอย่างที่ 1:

public bool MyFunction(myString: string){

    //guard block
    if (myString == null){
        return false;
    }
    else{
        //processing block
        myString = escapedString(myString);

        if (myString == "foo"){
            //some processing here
            return false;
        }
        else{
            myString = "Name " + myString;
            //other stuff
            return true;
        }
    }
}

ตัวอย่างที่ 2:

public bool MyFunction(myString: string){

    //guard block
    if (myString == null){
        return false;
    }

    //processing block
    myString = escapedString(myString);

    if (myString == "foo"){
        //some processing here
        return false;
    }
    else{
        myString = "Name " + myString;
        //other stuff
        return true;
    }
}

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

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

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


18
ตัวอย่างที่ 2 จะง่ายต่อการอ่านมากขึ้นถ้าคุณไม่ได้อ่านอีก
briddums

18

ส่วนตัวฉันชอบวิธีที่สอง ฉันรู้สึกว่ามันสั้นกว่ามีการเยื้องน้อยกว่าและอ่านง่ายกว่า


+1 สำหรับการเยื้องน้อย ท่าทางนี้ไม่สุภาพหากคุณมีเช็คหลายใบ
d.raev

15

การปฏิบัติส่วนตัวของฉันคือต่อไปนี้:

  • ฉันไม่ชอบฟังก์ชั่นที่มีจุดออกหลายแห่งฉันพบว่ามันยากที่จะรักษาและติดตามบางครั้งการแก้ไขโค้ดอาจทำให้ตรรกะภายในเสียหายได้ เมื่อเป็นการคำนวณที่ซับซ้อนฉันจะสร้างค่าตอบแทนที่จุดเริ่มต้นและส่งคืนในตอนท้าย สิ่งนี้บังคับให้ฉันต้องติดตามแต่ละ if-else สวิตช์ ฯลฯ เส้นทางอย่างระมัดระวังตั้งค่าอย่างถูกต้องในตำแหน่งที่เหมาะสม ฉันยังใช้เวลาเล็กน้อยในการตัดสินใจว่าจะตั้งค่าส่งคืนเริ่มต้นหรือไม่ปล่อยให้มันเป็นค่าเริ่มต้น วิธีนี้ยังช่วยเมื่อตรรกะหรือประเภทค่าตอบแทนหรือความหมายเปลี่ยนแปลง

ตัวอย่างเช่น:

public bool myFunction()
{
   // First parameter loading
   String myString = getString();

   // Location of "quick exits", see the second example
   // ...

   // declaration of external resources that MUST be released whatever happens
   // ...

   // the return variable (should think about giving it a default value or not) 
   // if you have no default value, declare it final! You will get compiler 
   // error when you try to set it multiple times or leave uninitialized!
   bool didSomething = false;

   try {
     if (myString != null)
     {
       myString = "Name " + myString;
       // Do something more here...

       didSomething = true;
     } else {
       // get other parameters and data
       if ( other conditions apply ) {
         // do something else
         didSomething = true;
       }
     }

     // Edit: previously forgot the most important advantage of this version
     // *** HOUSEKEEPING!!! ***

   } finally {

     // this is the common place to release all resources, reset all state variables

     // Yes, if you use try-finally, you will get here from any internal returns too.
     // As I said, it is only my taste that I like to have one, straightforward path 
     // leading here, and this works even if you don't use the try-finally version.

   }

   return didSomething;
}
  • ข้อยกเว้นเดียวเท่านั้น: "ออกอย่างรวดเร็ว" ที่เริ่มต้น (หรือในบางกรณีภายในกระบวนการ) หากตรรกะการคำนวณจริงไม่สามารถจัดการการรวมกันของพารามิเตอร์อินพุตและสถานะภายในหรือมีวิธีแก้ปัญหาอย่างง่ายโดยไม่ต้องใช้อัลกอริทึมมันไม่ได้ช่วยให้มีการห่อหุ้มโค้ดทั้งหมด (บางครั้งลึก) หากบล็อก นี่เป็น "สถานะพิเศษ" ไม่ใช่ส่วนหนึ่งของตรรกะหลักดังนั้นฉันต้องออกจากการคำนวณทันทีที่ฉันตรวจพบ ในกรณีนี้ไม่มีสาขาอื่นในสภาวะปกติการดำเนินการจะดำเนินต่อไป (แน่นอนว่า "สถานะพิเศษ" จะแสดงออกมาได้ดีกว่าโดยการโยนข้อยกเว้น แต่บางครั้งก็เป็น overkill)

ตัวอย่างเช่น:

public bool myFunction()
{
   String myString = getString();

   if (null == myString)
   {
     // there is nothing to do if myString is null
     return false;
   } 

   myString = "Name " + myString;
   // Do something more here...

   // not using return value variable now, because the operation is straightforward.
   // if the operation is complex, use the variable as the previous example.

   return true;
}

กฎ "one exit" ยังช่วยเมื่อการคำนวณต้องการทรัพยากรภายนอกที่คุณต้องปล่อยหรือระบุว่าคุณต้องรีเซ็ตก่อนออกจากฟังก์ชัน บางครั้งมีการเพิ่มภายหลังในระหว่างการพัฒนา ด้วยการออกหลายครั้งในอัลกอริทึมจึงเป็นการยากที่จะขยายสาขาทั้งหมดอย่างถูกต้อง (และหากมีข้อยกเว้นเกิดขึ้นควรปล่อย / รีเซ็ตในบล็อกในที่สุดเช่นกันเพื่อหลีกเลี่ยงผลข้างเคียงในกรณีพิเศษที่หายาก ... )

กรณีของคุณดูเหมือนจะตกอยู่ในหมวดหมู่ "ออกอย่างรวดเร็วก่อนที่จะทำงานจริง" และฉันจะเขียนมันเหมือนเวอร์ชัน 2 ตัวอย่างของคุณ


9
+1 สำหรับ "ฉันไม่ชอบฟังก์ชั่นที่มีหลายจุดออก"
Corv1nus

@LorandKedves - เพิ่มตัวอย่าง - หวังว่าคุณจะไม่สนใจ
Matthew Flynn

@ MatthewFlynn ดีถ้าคุณไม่รังเกียจว่ามันตรงข้ามกับสิ่งที่ฉันแนะนำในตอนท้ายของคำตอบของฉัน ;-) ฉันทำต่อไปฉันหวังว่าในที่สุดมันจะดีสำหรับเราทั้งคู่ :-)
Lorand Kedves

@ MatthewFlynn (ขออภัยฉันเป็นเพียง
ลูกครอกที่ไร้สาระ

13
ของฟังก์ชั่นที่มีจุดออกหลายจุดและฟังก์ชั่นที่มีตัวแปรผลลัพธ์ที่ไม่แน่นอนในอดีตดูเหมือนว่าฉันจะน้อยกว่าความชั่วสองอย่าง
Jon Purdy

9

ฉันชอบจ้างบล็อกป้องกันที่ฉันสามารถทำได้ด้วยเหตุผลสองประการ:

  1. พวกเขาอนุญาตให้ออกอย่างรวดเร็วเนื่องจากเงื่อนไขบางอย่าง
  2. ลบความจำเป็นสำหรับความซับซ้อนและไม่จำเป็นถ้าคำสั่งในรหัสในภายหลัง

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


5

ฉันชอบวิธี "Fall through":

public bool MyFunction()
{
   string myString = GetString();

   if (myString != null)
   {
     myString = "Name " + myString;
     return true;
    }
    return false;
}

การกระทำมีเงื่อนไขเฉพาะสิ่งอื่นใดเป็นเพียงการเริ่มต้น "ตกผ่าน"


1

ถ้าฉันมีเงื่อนไขเดียวฉันจะไม่ใช้เวลามากเกินไปในการพิจารณาสไตล์ แต่ถ้าฉันมีเงื่อนไขการป้องกันที่หลากหลายฉันต้องการสไตล์ 2

รูปนี้ สมมติว่าการทดสอบนั้นซับซ้อนและคุณไม่ต้องการผูกมันไว้ในเงื่อนไข if-ORed เดียวเพื่อหลีกเลี่ยงความซับซ้อน:

//Style1
if (this1 != Right)
{ 
    return;
}
else if(this2 != right2)
{
    return;
}
else if(this3 != right2)
{
    return;
}
else
{
    //everything is right
    //do something
    return;
}

กับ

//Style 2
if (this1 != Right)
{ 
   return;
}
if(this2 != right2)
{
    return;
}
if(this3 != right2)
{
    return;
}


//everything is right
//do something
return;

ที่นี่มีสองข้อได้เปรียบหลัก

  1. คุณกำลังแยกรหัสในฟังก์ชั่นเดียวออกเป็นสองบล็อก logcal ทางสายตา: บล็อกด้านบนของการตรวจสอบ (เงื่อนไขยาม) และบล็อกล่างของรหัสที่ทำงานได้

  2. หากคุณจำเป็นต้องเพิ่ม / ลบเงื่อนไขหนึ่งคุณจะลดโอกาสในการเลอะบันไดทั้งหมด

ข้อดีอีกข้อหนึ่งคือคุณมีเครื่องมือจัดฟันน้อยกว่าหนึ่งชุด


0

นี่ควรเป็นเรื่องที่ฟังดูดีกว่า

If condition
  do something
else
  do somethingelse

เป็นการแสดงออกถึงตัวเองดีขึ้นแล้ว

if condition
  do something
do somethingelse

สำหรับวิธีการขนาดเล็กมันจะไม่แตกต่างกันมาก แต่สำหรับวิธีการแบบผสมขนาดใหญ่มันสามารถทำให้ยากที่จะเข้าใจเพราะมันจะไม่แยกอย่างถูกต้อง


3
หากวิธีการหนึ่งนั้นยาวจนรูปแบบที่สองนั้นยากที่จะเข้าใจมันจะยาวเกินไป
วินไคลน์

7
ทั้งสองกรณีของคุณจะเทียบเท่าหากdo somethingรวมถึงการส่งคืน หากไม่มีรหัสที่สองจะทำงานdo somethingelseโดยไม่คำนึงถึงภาคifแสดงซึ่งไม่ใช่วิธีการทำงานของบล็อกแรก
Adnan

พวกเขายังเป็นสิ่งที่ OP อธิบายในตัวอย่างของเขา เพียงทำตามคำถาม
José Valente

0

ฉันพบตัวอย่างที่ 1 น่ารำคาญเพราะคำสั่งคืนที่หายไปในตอนท้ายของฟังก์ชั่นการคืนค่าจะกระตุ้นให้ "รอมีบางอย่างผิดปกติ" - แฟล็ก ดังนั้นในกรณีเช่นนี้ฉันจะไปกับตัวอย่างที่ 2

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


0

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


0

ในตัวอย่างของคุณelseเห็นได้ชัดว่าไม่จำเป็น แต่ ...

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

ในความคิดของฉันนี่เป็นหนึ่งในกรณีที่หายากเหล่านั้นซึ่งการเพิ่มสิ่งที่ซ้ำซ้อนลงในรหัสทำให้สามารถอ่านได้มากขึ้นไม่น้อย


0

ฉันไม่ต้องการตัวอย่างเช่น 2 เพราะมันเห็นได้ชัดทันทีว่าฟังก์ชั่นส่งกลับบางสิ่งบางอย่าง แต่ยิ่งไปกว่านั้นฉันอยากกลับจากที่แห่งนี้:

public bool MyFunction()
{
    bool result = false;

    string myString = GetString();

    if (myString != nil) {
        myString = "Name " + myString;

        result = true;
    }

    return result;
}

ด้วยสไตล์นี้ฉันสามารถ:

  1. ดูได้ทันทีว่าฉันคืนอะไร

  2. จับผลลัพธ์ของการเรียกใช้ฟังก์ชันทุกครั้งด้วยจุดพักเดียว


มันคล้ายกับว่าฉันจะแก้ไขปัญหาอย่างไร ข้อแตกต่างคือฉันจะใช้ตัวแปรผลลัพธ์เพื่อจับการประเมิน myString และใช้มันเป็นค่าตอบแทน
Chuck Conway

@ ChuckConway เห็นด้วย แต่ฉันพยายามที่จะยึดติดกับต้นแบบของ OP
Caleb

0

สไตล์ส่วนตัวของฉันมีแนวโน้มที่จะไป

function doQuery(string) {
    if (!query(string)) {
        query("ABORT");
        return false;
    } // else
    if(!anotherquery(string) {
        query("ABORT");
        return false;
    } // else
    return true;
}

การใช้elseคำสั่งcommented-out เพื่อระบุการไหลของโปรแกรมและทำให้อ่านได้ แต่หลีกเลี่ยงการเยื้องขนาดใหญ่ที่สามารถเข้าถึงผ่านหน้าจอได้อย่างง่ายดายหากมีขั้นตอนมากมายที่เกี่ยวข้อง


1
โดยส่วนตัวฉันหวังว่าฉันจะไม่ต้องทำงานกับรหัสของคุณ
CVn

หากคุณมีการตรวจสอบหลายวิธีวิธีนี้อาจใช้เวลานาน การส่งคืนจากแต่ละส่วนหากประโยคคล้ายกับการใช้คำสั่ง goto เพื่อข้ามส่วนของรหัส
Chuck Conway

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

0

ฉันจะเขียน

public bool SetUserId(int id)
{
   // Get user name from id
   string userName = GetNameById(id);

   if (userName != null)
   {
       // update local ID and userName
       _id = id;
       _userNameLabelText = "Name: " + userName;
   }

   return userName != null;
}

userName != nullผมชอบสไตล์นี้เพราะมันเป็นที่ชัดเจนที่สุดที่ฉันจะกลับมา


1
คำถามคือทำไมคุณถึงชอบสไตล์นั้น
คาเลบ

... ตรงไปตรงมาฉันไม่แน่ใจว่าทำไมคุณถึงต้องการสตริงในกรณีนี้ไม่ต้องพูดถึงว่าทำไมคุณถึงเพิ่มการทดสอบบูลีนพิเศษในตอนท้ายที่คุณไม่ต้องการด้วยเหตุผลใด ๆ ก็ตาม
Shadur

@Shadur ฉันรู้ว่าการทดสอบบูลีนพิเศษและmyStringผลลัพธ์ที่ไม่ได้ใช้ ฉันเพิ่งคัดลอกฟังก์ชั่นจาก OP ฉันจะเปลี่ยนเป็นสิ่งที่ดูสมจริงกว่า การทดสอบบูลีนนั้นไม่สำคัญและไม่ควรเป็นปัญหา
tia

1
@Shadur เราไม่ได้ทำการเพิ่มประสิทธิภาพที่นี่ใช่มั้ย จุดของฉันคือการทำให้รหัสของฉันง่ายต่อการอ่านและบำรุงรักษาและโดยส่วนตัวแล้วฉันจะจ่ายด้วยค่าใช้จ่ายของการตรวจสอบโมฆะอ้างอิงหนึ่ง
tia

1
@ เตี้ยฉันชอบจิตวิญญาณของรหัสของคุณ แทนการประเมินชื่อผู้ใช้สองครั้งฉันจะจับการประเมินครั้งแรกในตัวแปรแล้วคืนค่านั้น
Chuck Conway

-1

กฎง่ายๆของฉันคือการทำ if-return โดยไม่มีอย่างอื่น (ส่วนใหญ่เป็นข้อผิดพลาด) หรือทำ if-else - if chain เต็มไปหมด

วิธีนี้ฉันหลีกเลี่ยงการพยายามแฟนซีเกินไปกับการแตกแขนงของฉันเนื่องจากเมื่อใดก็ตามที่ฉันทำสิ่งที่ฉันเข้ารหัสตรรกะแอปพลิเคชันลงใน ifs ของฉันทำให้พวกเขายากที่จะรักษา (ตัวอย่างเช่นถ้า enum OK หรือ ERR และฉันเขียน ifs ทั้งหมดของฉัน การใช้ประโยชน์จากข้อเท็จจริงที่ว่า! ตกลง <-> ERR มันจะกลายเป็นความเจ็บปวดในตูดเพื่อเพิ่มตัวเลือกที่สามให้กับ enum ในครั้งต่อไป)

ตัวอย่างเช่นในกรณีของคุณฉันจะใช้แบบธรรมดาถ้าเนื่องจาก "return ถ้า null" เป็นรูปแบบทั่วไปและไม่น่าเป็นไปได้ที่คุณจะต้องกังวลเกี่ยวกับความเป็นไปได้ที่สาม (นอกเหนือจาก null / ไม่ใช่ null) ในอนาคต.

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


-1

ฉันคิดว่ามีข้อผิดพลาดมากมายในตัวอย่างที่ 2 ที่ถนนอาจนำไปสู่รหัสที่ไม่ได้ตั้งใจ สิ่งที่น่าสนใจอันดับหนึ่งที่นี่ขึ้นอยู่กับตรรกะรอบ ๆ ตัวแปร 'myString' ดังนั้นจะมีความชัดเจนการทดสอบเงื่อนไขทั้งหมดควรเกิดขึ้นในการบัญชีรหัสบล็อกสำหรับตรรกะที่รู้จักและเริ่มต้น / ไม่รู้จัก

จะเกิดอะไรขึ้นถ้ารหัสต่อมาถูกนำมาใช้โดยไม่ได้ตั้งใจกับตัวอย่าง 2 ที่เปลี่ยนแปลง ouput อย่างมีนัยสำคัญ:

   if (myString == null)
   {
      return false;
   }

   //add some v1 update code here...
   myString = "And the winner is: ";
   //add some v2 update code here...
   //buried in v2 updates the following line was added
   myString = null;
   //add some v3 update code here...
   //Well technically this should not be hit because myString = null
   //but we already passed that logic
   myString = "Name " + myString;
   // Do something more here...
   return true;

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

ฉันให้ความเชื่อมั่นในเรื่องนี้กับ C # guidlines บน Codeplex (ลิงก์ไปยังที่นี่: http://csharpguidelines.codeplex.com/ ) ซึ่งระบุสิ่งต่อไปนี้:

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

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


การไม่มีอีกตัวอย่างหนึ่งในสองนั้นไม่ได้นำมาพิจารณาในทุกกรณี? ผลลัพธ์ที่ต้องการคือดำเนินการต่อเนื่อง การเพิ่มส่วนคำสั่งอื่นในกรณีนี้เพิ่มความซับซ้อนของวิธีการเท่านั้น
Chuck Conway

ฉันไม่เห็นด้วยตามความสามารถในการไม่มีตรรกะที่เกี่ยวข้องทั้งหมดในคำถามในบล็อกที่กระชับและกำหนดขึ้น การมุ่งเน้นไปที่การจัดการmyStringค่าและรหัสที่ประสบความสำเร็จifบล็อกเป็นตรรกะที่เกิดขึ้นถ้าสตริง! = null ดังนั้นเนื่องจากการมุ่งเน้นไปที่ตรรกะเพิ่มเติมที่จัดการค่าเฉพาะนั้นฉันคิดว่ามันควรจะถูกห่อหุ้มในelseบล็อก ไม่เช่นนั้นจะเปิดโอกาสให้มากขึ้นเนื่องจากฉันแยกตรรกะโดยไม่ได้ตั้งใจและแนะนำผลที่ไม่ได้ตั้งใจ อาจไม่เกิดขึ้นตลอดเวลา แต่นี่เป็นคำถามสไตล์ความเห็นที่ดีที่สุด
atconway
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.