จะใช้คีย์เวิร์ดพ่นสไตล์ Java ใน C # ได้อย่างไร?


93

ใน Java throwsคีย์เวิร์ดอนุญาตให้มีเมธอดเพื่อประกาศว่าจะไม่จัดการข้อยกเว้นด้วยตัวมันเอง แต่จะโยนมันไปที่เมธอดการเรียก

มีคำหลัก / แอตทริบิวต์ที่คล้ายกันใน C # หรือไม่?

หากไม่มีสิ่งที่เทียบเท่าคุณจะทำเอฟเฟกต์เดียวกัน (หรือคล้ายกัน) ให้สำเร็จได้อย่างไร?

คำตอบ:


80

ใน Java คุณต้องจัดการกับข้อยกเว้นหรือทำเครื่องหมายวิธีการที่อาจทำให้เกิดข้อผิดพลาดโดยใช้throwsคีย์เวิร์ด

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

หากคุณต้องการจัดการมันให้โยนใหม่คุณสามารถทำสิ่งต่อไปนี้:

try
{
  // code that throws an exception
}
catch(ArgumentNullException ex)
{
  // code that handles the exception
  throw;
}

1
"มันจะขึ้น" หมายความว่านี่เทียบเท่ากับวิธีการทั้งหมดที่มีคำสั่งพ่นใน Java หรือไม่?
Louis Rhys

1
@ หลุยส์ RH - ชนิดของ. หมายความว่าข้อยกเว้นหากไม่ได้รับการจัดการจะเพิ่มสายโซ่การโทรผ่านแต่ละฟังก์ชันการโทรจนกว่าจะได้รับการจัดการ
Oded

1
@Louis RH ไม่สมบูรณ์นั่นหมายความว่าคุณต้องจับ Exception อย่างน้อยในตัวคุณหลักเพื่อคอมไพล์โค้ด เนื่องจาก C # ไม่ทราบข้อยกเว้นที่ตรวจสอบแล้วจึงขึ้นอยู่กับคุณที่จะตรวจจับไม่เช่นนั้นพวกเขาจะเข้าสู่รันไทม์และขัดจังหวะรหัสของคุณ
Johannes Wachter

1
@jwatcher: วิธีการหลักสามารถมีคำสั่งโยนได้เช่นกัน
Louis Rhys

4
@AshishKamble - เอ๊ะ. เรื่องของความคิดเห็น การจัดการข้อยกเว้นแตกต่างกันใน. NET อย่าคิดว่าคุณรู้ว่าอะไร "ดีกว่า"
Oded

109

op กำลังถามเกี่ยวกับC # ที่เทียบเท่ากับthrowsอนุประโยคของ Javaไม่ใช่throwคำหลัก สิ่งนี้ใช้ในลายเซ็นเมธอดใน Java เพื่อระบุว่าสามารถโยนข้อยกเว้นที่ตรวจสอบได้

ใน C # ไม่มีข้อยกเว้นที่เทียบเท่ากับ Java ที่ตรวจสอบโดยตรง C # ไม่มีประโยคลายเซ็นวิธีเทียบเท่า

// Java - need to have throws clause if IOException not handled
public void readFile() throws java.io.IOException {
  ...not explicitly handling java.io.IOException...
}

แปลเป็น

// C# - no equivalent of throws clause exceptions are unchecked
public void ReadFile() 
{
  ...not explicitly handling System.IO.IOException...
}

31

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

หากคุณใช้ Visual Studio 2012 มีเครื่องมือในตัวที่สามารถใช้เพื่ออนุญาตให้เทียบเท่าระดับ IDE "พ่น" ได้

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

ตัวอย่าง:

    /// <summary>This method throws an exception.</summary>
    /// <param name="myPath">A path to a directory that will be zipped.</param>
    /// <exception cref="IOException">This exception is thrown if the archive already exists</exception>
    public void FooThrowsAnException (string myPath)
    {
        // This will throw an IO exception
        ZipFile.CreateFromDirectory(myPath);
    }

4
OP นี่คือคำตอบของคุณ ฉันคาดเดา แต่ JAVA throwsน่าจะไม่มีความหมายอะไรกับรันไทม์นอกเหนือจากการให้ข้อมูลแก่ผู้พัฒนา ในทำนองเดียวกันสิ่งที่ @mvanella ชี้ให้เห็นนี่คือวิธีของ C # ในการทำเช่นเดียวกัน ฉันสมมติว่าคุณรู้อยู่แล้วว่า "เอกสาร xml" นี้มีจุดประสงค์ที่สำคัญกว่า ฉันรู้ว่ากระทู้นี้เก่าแล้ว
Hari Lubovac

อันที่จริง, Java ไม่ฟองขึ้นยกเว้นจนกว่าจะมีการระบุไว้อย่างชัดเจนในthrowsข้อหรือโยนโดยthrowคำสั่ง นั่นหมายความว่าหาก RunTimeException เกิดขึ้นและไม่ได้รับการจัดการในวิธีการเดียวกันกับที่เกิดขึ้นการดำเนินการจะหยุดที่นั่น
Pedro Lima

19

นี่คือคำตอบสำหรับคำถามที่คล้ายกันที่ฉันพบในbytes.com :

คำตอบสั้น ๆ คือไม่ ไม่มีการตรวจสอบข้อยกเว้นใน C # ผู้ออกแบบภาษากล่าวถึงการตัดสินใจในการสัมภาษณ์ครั้งนี้:

http://www.artima.com/intv/handcuffs.html

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


7

หลังจากอ่านคำตอบส่วนใหญ่แล้วฉันต้องการเพิ่มความคิดสองสามข้อ

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

  2. Andreas เชื่อมโยงการสัมภาษณ์กับ Anders Hejlsberg ในคำตอบที่นี่เกี่ยวกับสาเหตุที่ทีมออกแบบ C # ตัดสินใจไม่ใช้ข้อยกเว้นที่ตรวจสอบแล้ว คำตอบที่ดีที่สุดสำหรับคำถามเดิมซ่อนอยู่ในการสัมภาษณ์นั้น:

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

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

-

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


3

จริงๆแล้วไม่ได้ตรวจสอบข้อยกเว้นใน C # ถือได้ว่าเป็นสิ่งที่ดีหรือไม่ดี

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

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

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

try {
    // Some Code
} catch(SomeException ex){
    throw new RuntimeException(ex);
}

ซึ่งโดยพื้นฐานแล้วหมายถึงการเลียนแบบวิธีที่ C # / NET จัดการกับข้อยกเว้นทั้งหมด


ฉันนึกไม่ออกว่าข้อยกเว้นที่ตรวจสอบแล้วจะผสมกับ lambdas ได้อย่างไร!
Gabe

@Gabe: ฉันแน่ใจว่าคุณสามารถคิดแนวคิดบางอย่างที่ช่วยให้คุณผสมมันได้ แต่อย่างที่ฉันพูดไปการตรวจสอบข้อยกเว้นใน Java ส่วนใหญ่ไม่ใช่แนวทางปฏิบัติที่ดีโดยเฉพาะอย่างยิ่งในแอปพลิเคชันที่ซับซ้อนมากขึ้น ดังนั้นจึงเป็นเรื่องดีที่พวกเขาไม่มีใน C #
Johannes Wachter

3

คุณกำลังถามเกี่ยวกับสิ่งนี้:

โยนข้อยกเว้นอีกครั้ง

public void Method()
{
  try
  {
      int x = 0;
      int sum = 100/x;
  }
  catch(DivideByZeroException e)
  {
      throw;
  }
}

หรือ

static void Main() 
    {
        string s = null;

        if (s == null) 
        {
            throw new ArgumentNullException();
        }

        Console.Write("The string s is null"); // not executed
    }

3
+1 throwสำหรับใช้ ด้วยการใช้สแต็กแทร็กจะไม่สูญหาย
Giuseppe Accaputo

2

มีความคล้ายคลึงกันบางอย่างระหว่าง. Net CodeContract EnsuresOnThrow<>และ java throwsdescriptor โดยที่ทั้งสองสามารถส่งสัญญาณไปยังผู้เรียกเป็นประเภทของข้อยกเว้นซึ่งสามารถยกขึ้นจากฟังก์ชันหรือวิธีการแม้ว่าจะมีความแตกต่างที่สำคัญระหว่าง 2:

  • EnsuresOnThrow<>นอกเหนือไปจากการระบุว่าสามารถโยนข้อยกเว้นใดได้ แต่ยังกำหนดเงื่อนไขที่รับประกันว่าจะถูกโยนซึ่งอาจเป็นรหัสที่ค่อนข้างลำบากในวิธีการที่เรียกว่าหากเงื่อนไขข้อยกเว้นไม่สำคัญที่จะระบุ Java throwsแสดงข้อบ่งชี้ว่าอาจมีข้อยกเว้นใดบ้าง (เช่น IMO โฟกัสใน. Net อยู่ในวิธีการที่ทำสัญญาเพื่อพิสูจน์throwขณะที่ใน Java โฟกัสจะเปลี่ยนไปยังผู้เรียกเพื่อรับทราบถึงความเป็นไปได้ของข้อยกเว้น)
  • . Net CC ไม่ได้สร้างความแตกต่างระหว่างข้อยกเว้นที่ตรวจสอบและไม่ได้ตรวจสอบที่ Java มีแม้ว่าคู่มือ CC ส่วน 2.2.2 จะกล่าวถึง

"ใช้เงื่อนไขหลังพิเศษเฉพาะสำหรับข้อยกเว้นที่ผู้โทรควรคาดหวังว่าเป็นส่วนหนึ่งของ API"

  • ใน. Net ผู้โทรสามารถกำหนดได้ว่าจะทำสิ่งใดโดยมีข้อยกเว้นหรือไม่ (เช่นโดยการปิดสัญญา) ใน Java ผู้เรียกต้องทำบางสิ่งแม้ว่าจะเพิ่มthrowsข้อยกเว้นเดียวกันบนอินเทอร์เฟซก็ตาม

คู่มือ Code Contracts ที่นี่


0

หากจุดประสงค์ของเมธอด c # คือการโยนข้อยกเว้นเท่านั้น (เช่น js return type กล่าว) ฉันขอแนะนำให้ส่งคืนข้อยกเว้นนั้น ดูตัวอย่างการร้อง:

    public EntityNotFoundException GetEntityNotFoundException(Type entityType, object id)
    {
        return new EntityNotFoundException($"The object '{entityType.Name}' with given id '{id}' not found.");
    }

    public TEntity GetEntity<TEntity>(string id)
    {
        var entity = session.Get<TEntity>(id);
        if (entity == null)
            throw GetEntityNotFoundException(typeof(TEntity), id);
        return entity;
    }


-1

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

try {
    //your code here
}
catch {
    //this will throw any exceptions caught by this try/catch
    throw;
}

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