เมื่อใดและเพราะเหตุใดคุณจึงควรใช้ช่องว่าง (แทนเช่น bool / int)


30

ฉันพบวิธีในบางครั้งที่ผู้พัฒนาเลือกที่จะคืนสิ่งที่ไม่สำคัญกับฟังก์ชั่น ฉันหมายถึงเมื่อดูที่รหัสดูเหมือนว่าจะทำงานได้ดีพอ ๆ กับvoidหลังจากที่ฉันคิดว่า "ทำไม" เสียงนี้คุ้นเคยไหม?

บางครั้งผมก็จะเห็นว่าส่วนใหญ่มักจะดีกว่าที่จะกลับมาสิ่งที่ต้องการboolหรือมากกว่าแล้วก็ทำint voidฉันไม่แน่ใจว่าในภาพรวมเกี่ยวกับข้อดีข้อเสีย

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

ในทางกลับกัน,

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

คุณมีประสบการณ์อะไรกับเรื่องนี้? คุณจะทำสิ่งนี้อย่างไร


1
ฟังก์ชั่นที่ส่งกลับเป็นโมฆะไม่ใช่ฟังก์ชั่นทางเทคนิคเลย มันเป็นเพียงวิธี / ขั้นตอน การส่งคืนvoidอย่างน้อยทำให้นักพัฒนาซอฟต์แวร์ทราบว่ามูลค่าการส่งคืนของวิธีนั้นไม่สำคัญ มันเป็นการกระทำมากกว่าการคำนวณคุณค่า
KChaloux

คำตอบ:


32

ในกรณีของค่าส่งคืน bool เพื่อระบุความสำเร็จหรือความล้มเหลวของวิธีการฉันชอบ - Tryกระบวนทัศน์การแก้ไขที่ใช้ในวิธีการต่าง ๆ ใน. NET

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


4
+1 สำหรับการสร้างความแตกต่างระหว่างการจัดการกับความล้มเหลวที่คาดหวังและไม่คาดคิด - คำตอบของฉันไม่ได้เน้นสิ่งนี้มากพอ
PéterTörök

+1 อย่างแน่นอนสำหรับการพยายามคิดค้นหลักการสำหรับวิธี TryXX ซึ่งทำให้ทั้งสองวิธีลองและวิธีหลักง่ายต่อการบำรุงรักษาและง่ายต่อการเข้าใจวัตถุประสงค์ของพวกเขา
อิสระ

+1 ก็บอกว่า กุญแจสำคัญในคำตอบที่ดีที่สุดสำหรับคำถามนี้คือบางครั้งคุณต้องการให้ผู้โทรเลือกวิธีการแสดงออกที่เหมาะสมซึ่งจะทำให้เกิดข้อยกเว้น ในกรณีเหล่านี้แม้ว่าไม่ควรตรวจจับข้อยกเว้นและจัดการของปลอมโดยวิธีการแสดงออกที่เหมาะสม ประเด็นก็คือผู้โทรต้องรับผิดชอบ ในทางกลับกัน Try-paradigm (หรือ Monad) ควรจับและจัดการข้อยกเว้นจากนั้นส่งคืนบูลหรือ Enum เชิงพรรณนาหากต้องการรายละเอียดเพิ่มเติม โปรดทราบว่าผู้โทรคาดว่าการลอง / Monad จะไม่ส่งข้อยกเว้น มันเหมือนเป็นจุดเริ่มต้น
Suamere

ดังนั้นเนื่องจากข้อยกเว้นคาดว่าจะไม่เกิดขึ้นจาก Try / Monad แต่ bool นั้นไม่สามารถอธิบายได้เพียงพอที่จะแจ้งให้ผู้โทรทราบว่าการเชื่อมต่อ db ล้มเหลวหรือการร้องขอ http มีหนึ่งในค่าส่งคืนที่จำเป็นต่อการดำเนินการแตกต่างกัน คุณสามารถใช้ Enum แทนบูลสำหรับ Try / Monad ของคุณ
Suamere

หากคุณมี TryInsertRow - ส่งคืนบูล - ถ้ามีข้อ จำกัด ที่ไม่ซ้ำใครในฐานข้อมูล - คุณจะรู้ได้อย่างไรว่าเกิดข้อผิดพลาดอะไรขึ้นและสื่อสารกับผู้ใช้อย่างไร ควรใช้ประเภทการส่งคืนที่สมบูรณ์ยิ่งขึ้นที่มีข้อความแสดงข้อผิดพลาด / รหัส & บูลสำเร็จหรือไม่?
niico

28

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

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

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


4
+1 สำหรับข้อยกเว้นรหัสสถานะ ข้อยกเว้น (มีจุดประสงค์เพื่อจุดประสงค์ไม่เหมาะสม) สำหรับรูปแบบนี้เป็นรูปแบบ TryXX ที่ใช้กันเป็นอย่างดี
Andy Lowry

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

ข้อมูลเพิ่มเติม +1 คือสาเหตุที่ฉันใช้วิธีนี้ในภาษาระดับสูงกว่าเช่น C # ทำให้ง่ายต่อการใช้ข้อมูลเพิ่มเติมเมื่อคุณต้องการ
ashes999

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

1
และใครที่จะบอกว่าข้อยกเว้นที่ถูกส่งออกไปจะไม่ถูกสังเกตเห็น? ไม่มีอะไรบังคับให้ใครเข้าสู่บล็อก catch ทำไมไม่เข้าสู่บล็อก "แล้ว"? ทำไม "บันทึกข้อยกเว้นวิธีการที่อาจเกิดขึ้นและเมื่อใด" ถ้าเราเขียนโค้ดการทำ self-document และเมธอดจะส่งคืน enum โดยใช้ end-state ที่คาดไว้ของเมธอดนั้น? หากมีข้อยกเว้นที่เป็นไปได้สามารถหลีกเลี่ยงได้โดยการตรวจสอบสถานะพวกเขาควรจะถูกจับและจัดการโดยไม่โยน
Suamere

14

คำตอบของปีเตอร์ครอบคลุมข้อยกเว้นอย่างดี การพิจารณาอื่น ๆ ที่นี่เกี่ยวข้องกับการแยกคำสั่งการค้นหา

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

มีบางกรณีที่ถูกละเมิดหลักการ CQS เป็นความคิดที่ดี เหล่านี้มักจะมีประสิทธิภาพหรือความปลอดภัยของเธรด


1
-1 ผิดและผิด ประการแรกจุดรวมทั้งหมดของ CQS อยู่ในคิวผู้โทรควรสามารถรับการคำนวณหรือการโทรภายนอกผ่านบริการไร้สัญชาติโดยไม่ต้องกลัวว่าจะเปลี่ยนสถานะของบริการนั้น นอกจากนี้ในขณะที่ CQS เป็นหลักการที่มีประโยชน์ในการติดตามอย่างหลวม ๆ มันเป็นเพียงการปฏิบัติตามอย่างเคร่งครัดในการออกแบบเฉพาะ สุดท้ายแม้ใน CQS เข้มงวดไม่มีอะไรบอกว่าคำสั่งไม่สามารถคืนค่ามันบอกว่ามันไม่ควรจะคำนวณหรือโทรคำนวณภายนอกและกลับข้อมูล ทั้ง C หรือ Q สามารถกลับสถานะสิ้นสุดของพวกเขาหากเป็นประโยชน์สำหรับผู้โทร
Suamere

อ่า แต่จำนวนแถวที่ได้รับผลกระทบจากคำสั่งทำให้การสร้างคำสั่งใหม่จากเดิมนั้นง่ายกว่ามาก ที่มา: ประสบการณ์หลายปี
Joshua

@Joshua: เช่นเดียวกัน "เพิ่มระเบียนใหม่และส่งกลับ ID (สำหรับบางโครงสร้างหมายเลขแถว) ที่สร้างขึ้นในระหว่างการเพิ่ม" สามารถใช้สำหรับวัตถุประสงค์ที่ไม่สามารถทำได้อย่างมีประสิทธิภาพ
supercat

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

3

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


+1 สิ่งนี้ไม่ตอบคำถามแต่เป็นข้อมูลที่ถูกต้องแน่นอน เมื่อทำการตัดสินใจการตัดสินใจควรขึ้นอยู่กับความต้องการ หากผู้โทรไม่พบข้อมูลที่ส่งคืนมีประโยชน์ก็ไม่ควรทำ และไม่มีใครพบว่าใช้ในการส่งคืนจริง 100% ของเวลาสำหรับ "พิสูจน์อักษรในอนาคต" จริงอยู่ถ้า "อนาคต" เป็นเช่น ... สองสามวันนับจากนี้และมีงานที่ทำอยู่นั่นคือเรื่องราวที่แตกต่าง lol
Suamere

1

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


1
วิธีการผูกมัดสามารถทำให้การสืบทอดมีความยุ่งยากและยากลำบากได้ ฉันจะไม่ทำวิธีการผูกมัดเว้นแต่คุณจะมีเหตุผลที่ดีที่จะทำอย่างอื่นนอกเหนือจากที่ไม่ต้องการให้วิธีการของคุณ "โมฆะ"
KallDrexx

จริง แต่การสืบทอดอาจยุ่งยากและใช้งานยาก
ไวแอตต์บาร์เน็ตต์

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

ฉันไม่คิดว่าคุณจะไปRubyถึงจุดหนึ่ง? นั่นคือสิ่งที่แนะนำให้ฉันรู้จักกับวิธีการผูกมัด
KChaloux

qualm ที่ฉันมีด้วยการโยงวิธีคือมันทำให้ชัดเจนน้อยลงว่าข้อความเช่นreturn Thing.Change1().Change2();คาดว่าจะเปลี่ยนThingและส่งกลับการอ้างอิงถึงต้นฉบับหรือคาดว่าจะกลับการอ้างอิงถึงสิ่งใหม่ที่แตกต่างจากต้นฉบับในขณะที่ออกจาก ต้นฉบับมิได้ถูกแตะต้อง
supercat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.