มีเหตุผลที่ถูกต้องหรือไม่ในการส่งคืนออบเจ็กต์ข้อยกเว้นแทนที่จะโยนมัน?


45

คำถามนี้มีวัตถุประสงค์เพื่อนำไปใช้กับภาษาการเขียนโปรแกรม OO ใด ๆ ที่รองรับการจัดการข้อยกเว้น; ฉันใช้ C # เพื่อเป็นตัวอย่างเท่านั้น

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

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

คำถามนี้เกิดขึ้นสำหรับฉันเพราะSystem.IObserver<T>.OnErrorวิธีของ. NET 4 แนะนำเพียงว่า: ข้อยกเว้นถูกส่งผ่านเป็นวัตถุข้อผิดพลาด

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

partial interface IValidationError { }

abstract partial class ValidationException : System.Exception
{
    public abstract IValidationError[] ValidationErrors { get; }
}

( System.Component.DataAnnotationsเนมสเปซทำอะไรที่ค่อนข้างคล้ายกัน)

ประเภทเหล่านี้สามารถใช้งานได้ดังนี้:

partial interface IFoo { }  // an immutable type

partial interface IFooBuilder  // mutable counterpart to prepare instances of above type
{
    bool IsValid(out IValidationError[] validationErrors);  // true if no validation error occurs
    IFoo Build();  // throws ValidationException if !IsValid(…)
}

ตอนนี้ฉันสงสัยว่าฉันไม่สามารถทำให้สิ่งข้างต้นนี้ง่ายขึ้นได้ไหม:

partial class ValidationError : System.Exception { }  // = IValidationError + ValidationException

partial interface IFoo { }  // (unchanged)

partial interface IFooBuilder
{
    bool IsValid(out ValidationError[] validationErrors);
    IFoo Build();  // may throw ValidationError or sth. like AggregateException<ValidationError>
}

ถาม:ข้อดีและข้อเสียของวิธีการที่ต่างกันทั้งสองนี้คืออะไร


หากคุณกำลังหาคำตอบแยกกันสองข้อคุณควรถามคำถามสองข้อแยกกัน การรวมเข้าด้วยกันทำให้ยากที่จะตอบ
Bobson

2
@ Bobon: ฉันเห็นว่าทั้งสองคำถามเป็นส่วนเสริม: คำถามเดิมควรจะกำหนดบริบททั่วไปของปัญหาในวงกว้างในขณะที่หลังขอข้อมูลเฉพาะที่ควรอนุญาตให้ผู้อ่านสรุปของตัวเอง คำตอบไม่จำเป็นต้องให้คำตอบแยกต่างหากสำหรับทั้งสองคำถาม คำตอบ "ในระหว่าง" เป็นเพียงยินดีต้อนรับ
stakx

5
ฉันไม่แน่ใจเกี่ยวกับบางสิ่ง: สาเหตุของการได้รับ ValidationError จาก Exception คืออะไรถ้าคุณไม่โยนมัน
pdr

@pdr: คุณหมายถึงในกรณีของการขว้างปาAggregateExceptionแทนหรือเปล่า? จุดดี.
stakx

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

คำตอบ:


31

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

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

ฟังก์ชั่นนี้ใช้สำหรับส่งคืนวัตถุยกเว้นหรือไม่

อย่างแน่นอน นี่คือรายการสั้น ๆ ของตัวอย่างที่อาจเหมาะสม:

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

การขว้างมันไม่ดีเหรอ?

การโยนข้อยกเว้นเป็นสิ่งที่ชอบ: "ไปเข้าคุกอย่าผ่านไป!" ในเกมกระดานผูกขาด มันบอกคอมไพเลอร์ให้กระโดดข้ามซอร์สโค้ดทั้งหมดจนถึงตัวดักจับโดยไม่ต้องรันซอร์สโค้ดใด ๆ มันไม่มีอะไรเกี่ยวข้องกับข้อผิดพลาดการรายงานหรือการหยุดบั๊ก ฉันชอบคิดว่าการโยนข้อยกเว้นเป็นคำสั่ง "super return" สำหรับฟังก์ชั่น มันคืนค่าการเรียกใช้โค้ดไปยังที่สูงกว่าผู้โทรเดิม

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

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


4
"ถ้ามันไม่เคยถูกโยนออกไปมันก็ไม่ใช่ข้อยกเว้นมันเป็นวัตถุที่ได้มาจากExceptionคลาส แต่ไม่ทำตามพฤติกรรม" - และนั่นคือปัญหา: มันถูกต้องหรือไม่ที่จะใช้Exceptionวัตถุที่ได้รับการถ่ายทอดในสถานการณ์ที่มันจะไม่ถูกโยนเลยไม่ว่าจะโดยผู้ผลิตวัตถุหรือโดยวิธีการโทรใด ๆ จะทำหน้าที่เป็น "ข้อความสถานะ" เท่านั้นที่ถูกส่งผ่านโดยไม่มีการควบคุม "super return" หรือฉันกำลังละเมิดข้อตกลงtry/ catch(Exception)สัญญาที่ไม่ได้พูดอย่างเลวร้ายจนฉันไม่ควรทำเช่นนี้และใช้Exceptionประเภทที่ไม่ใช่ประเภทอื่นแทน?
stakx

10
@stakx โปรแกรมเมอร์มีและจะยังคงทำสิ่งต่าง ๆ ที่สร้างความสับสนให้โปรแกรมเมอร์อื่น ๆ แต่ไม่ถูกต้องทางเทคนิค นั่นเป็นเหตุผลที่ฉันพูดว่ามันเป็นความหมาย คำตอบทางกฎหมายคือNoคุณไม่ได้ทำสัญญาใด ๆ popular opinionจะเป็นที่คุณไม่ควรทำอย่างนั้น การเขียนโปรแกรมเต็มไปด้วยตัวอย่างที่ซอร์สโค้ดของคุณไม่ได้ทำอะไรผิด แต่ทุกคนไม่ชอบมัน ควรเขียนซอร์สโค้ดเสมอเพื่อให้ชัดเจนว่าเจตนาคืออะไร คุณช่วยโปรแกรมเมอร์คนอื่นโดยใช้ข้อยกเว้นแบบนั้นหรือไม่? ถ้าใช่ก็ทำเช่นนั้น มิฉะนั้นอย่าแปลกใจถ้ามันไม่ชอบ
ซ้ำ

@cgTag การใช้บล็อคโค้ดแบบอินไลน์สำหรับตัวเอียงทำให้สมองของฉันเจ็บ ..
Frayt

51

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

กรณีใช้ที่เป็นไปได้หนึ่งอย่างอาจเป็นฟังก์ชันที่เปลี่ยนรหัสตอบกลับ HTTPเป็นข้อยกเว้น:

Exception analyzeHttpError(int errorCode) {
    if (errorCode < 400) {
         throw new NotAnErrorException();
    }
    switch (errorCode) {
        case 403:
             return new ForbiddenException();
        case 404:
             return new NotFoundException();
        case 500:
             return new InternalServerErrorException();
        …
        default:
             throw new UnknownHttpErrorCodeException(errorCode);
     }
}

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


สิ่งนี้ยังช่วยให้คอมไพเลอร์เข้าใจการไหลของรหัส: หากวิธีไม่เคยส่งคืนอย่างถูกต้อง (เพราะมันโยนข้อยกเว้น "ที่ต้องการ") และคอมไพเลอร์ไม่ทราบเกี่ยวกับเรื่องนั้นแล้วบางครั้งคุณอาจต้องมีreturnคำสั่ง
Joachim Sauer

@JoachimSauer ใช่ มากกว่าหนึ่งครั้งที่ฉันหวังว่าพวกเขาจะเพิ่มประเภทการคืนของ "ไม่เคย" ลงใน C # - มันจะบ่งบอกว่าฟังก์ชั่นจะต้องออกโดยการขว้างวางผลตอบแทนในนั้นเป็นข้อผิดพลาด บางครั้งคุณมีรหัสที่งานเดียวที่สวยขึ้นเป็นข้อยกเว้น
Loren Pechtel

2
@LorenPechtel ฟังก์ชั่นที่ไม่กลับมาไม่ใช่ฟังก์ชั่น มันเป็นเทอร์มินอล เรียกใช้ฟังก์ชันเช่นนั้นเพื่อล้างสแต็กการเรียก System.Exit()มันคล้ายกับการโทร รหัสหลังจากเรียกใช้ฟังก์ชันไม่ได้ถูกเรียกใช้ ไม่ฟังดูเหมือนรูปแบบการออกแบบที่ดีสำหรับฟังก์ชั่น
ปฏิกิริยา

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

1
@ LorenPechtel อ่าฉันก็ทำไปแล้วเหมือนกัน โอเคฉันเข้าใจแล้ว
ซ้ำ

5

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

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

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


ฉันไม่คิดว่าจะมีคนที่มีชื่อเสียงคนใดสนับสนุนรูปแบบดังกล่าวในรูปแบบ "ลอง" แต่วิธี "แนะนำ" ในการส่งคืนบูลีนนั้นดูเหมือนว่าจะเป็นเรื่องเกี่ยวกับโลหิตจาง ฉันคิดว่ามันจะดีกว่าถ้ามีOperationResultคลาสนามธรรมพร้อมboolคุณสมบัติ "Successful" GetExceptionIfAnyวิธีการและAssertSuccessfulเมธอด (ซึ่งจะทำให้เกิดข้อยกเว้นจากGetExceptionIfAnyถ้าไม่ใช่โมฆะ) มีGetExceptionIfAnyวิธีการมากกว่าคุณสมบัติจะอนุญาตให้ใช้วัตถุข้อผิดพลาดไม่เปลี่ยนรูปแบบคงที่สำหรับกรณีที่ไม่มีประโยชน์มากที่จะพูด
supercat

5

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

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

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

PS: สิ่งนี้ถูกเขียนด้วยประสบการณ์กับ Java โดยที่ข้อมูลการติดตามสแต็กจะถูกสร้างขึ้นเมื่อมีการสร้างข้อยกเว้น (ซึ่งแตกต่างจาก C # ที่สร้างขึ้นเมื่อมีการขว้างปา) ดังนั้นอย่าใช้วิธีการยกเว้นใน Java จะช้ากว่าใน C # (เว้นแต่จะถูกสร้างขึ้นมาใหม่และนำกลับมาใช้ใหม่) แต่จะมีข้อมูลการติดตามสแต็ก

โดยทั่วไปแล้วฉันจะอยู่ห่างจากการสร้างข้อยกเว้นและไม่เคยทิ้งมัน (เว้นแต่จะเป็นการเพิ่มประสิทธิภาพการทำงานหลังจากการทำโปรไฟล์ชี้ให้เห็นว่าเป็นคอขวด) อย่างน้อยใน java ที่การสร้างข้อยกเว้นมีราคาแพง (การติดตามสแต็ก) ใน C # เป็นไปได้ แต่ IMO นั้นน่าประหลาดใจและควรหลีกเลี่ยง


สิ่งนี้มักจะเกิดขึ้นกับวัตถุฟังข้อผิดพลาดเช่นกัน คิวจะดำเนินงานจับข้อยกเว้นใด ๆ แล้วส่งข้อยกเว้นนั้นไปยังผู้ฟังข้อผิดพลาดที่รับผิดชอบ ปกติแล้วมันจะไม่สมเหตุสมผลที่จะฆ่าเธรดภารกิจที่ไม่ทราบมากเกี่ยวกับงานในกรณีนี้ ความคิดประเภทนี้ถูกสร้างขึ้นใน Java APIs ซึ่งหนึ่งเธรดสามารถรับการส่งผ่านข้อยกเว้นจากอีก: docs.oracle.com/javase/1.5.0/docs/api/java/lang/…
Lance Nanek

1

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

        private static void ProcessFileFailFast()
        {
            try
            {
                using (var file = new System.IO.StreamReader("c:\\test.txt"))
                {
                    string line;
                    while ((line = file.ReadLine()) != null)
                    {
                        ProcessLine(line);
                    }
                }
            }
            catch (Exception ex) 
            {
                LogException(ex);
            }
        }

        private static void ProcessLine(string line)
        {
            //TODO:  Process Line
        }

        private static void LogException(Exception ex)
        {
            //TODO:  Log Exception
        }

ในกรณีนี้เราจะผิดพลาดและหยุดการประมวลผลไฟล์ทันทีที่พบบันทึกที่ไม่ดี

แต่บอกว่าความต้องการคือเราต้องการดำเนินการประมวลผลไฟล์ต่อไปแม้ว่าหนึ่งหรือมากกว่าหนึ่งบรรทัดมีข้อผิดพลาด รหัสอาจเริ่มมีลักษณะดังนี้:

    private static void ProcessFileFailAndContinue()
    {
        try
        {
            using (var file = new System.IO.StreamReader("c:\\test.txt"))
            {
                string line;
                while ((line = file.ReadLine()) != null)
                {
                    Exception ex = ProcessLineReturnException(line);
                    if (ex != null)
                    {
                        _Errors.Add(ex);
                    }
                }
            }

            //Do something with _Errors Here
        }
        //Catch errors specifically around opening the file
        catch (System.IO.FileNotFoundException fnfe) 
        { 
            LogException(fnfe);
        }    
    }

    private static Exception ProcessLineReturnException(string line)
    {
        try
        {
            //TODO:  Process Line
        }
        catch (Exception ex)
        {
            LogException(ex);
            return ex;
        }

        return null;
    }

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

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


1

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

ใช่. ตัวอย่างเช่นเมื่อเร็ว ๆ นี้ฉันพบสถานการณ์ของสถานการณ์ที่ฉันพบว่าการโยนข้อยกเว้นใน ASMX donot บริการเว็บรวมองค์ประกอบในข้อความ SOAP ผลลัพธ์ดังนั้นฉันต้องสร้างมันขึ้นมา

รหัสตัวอย่าง:

Public Sub SomeWebMethod()
    Try
        ...
    Catch ex As Exception
        Dim soapex As SoapException = Me.GenerateSoapFault(ex)
        Throw soapex
    End Try
End Sub

Private Function GenerateSoapFault(ex As Exception) As SoapException
    Dim document As XmlDocument = New XmlDocument()
    Dim faultDetails As XmlNode = document.CreateNode(XmlNodeType.Element, SoapException.DetailElementName.Name, SoapException.DetailElementName.Namespace)
    faultDetails.InnerText = ex.Message
    Dim exceptionType As String = ex.GetType().ToString()
    Dim soapex As SoapException = New SoapException("SoapException", SoapException.ClientFaultCode, Context.Request.Url.ToString, faultDetails)
    Return soapex
End Function

1

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

ตามที่ @ThinkingMedia ได้กล่าวไปแล้วคุณใช้ข้อยกเว้นนี้เป็นวัตถุข้อผิดพลาดจริงๆ

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

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

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

ดังนั้นมันเป็นความคิดที่ดีหรือไม่?

จนถึงตอนนี้ฉันยังไม่เห็นว่ามันถูกใช้หรือแนะนำ แต่มันก็ไม่ได้มีความหมายอะไรมาก

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

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


-4

คำตอบคือใช่ ดูhttp://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Exceptionsและเปิดลูกศรสำหรับแนวทางสไตล์ C ++ ของ Google ในข้อยกเว้น คุณสามารถเห็นการโต้เถียงที่พวกเขาเคยตัดสินใจ แต่พูดว่าถ้าพวกเขาต้องทำมันอีกครั้งพวกเขาก็น่าจะตัดสินใจแล้ว

อย่างไรก็ตามเป็นเรื่องที่น่าสังเกตว่าภาษาโกไม่ได้ใช้ข้อยกเว้นอย่างมีเหตุผลด้วยเหตุผลเดียวกัน


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