Làm cách nào để sử dụng từ khóa ném kiểu Java trong C #?


89

Trong Java, throwstừ khóa cho phép một phương thức khai báo rằng nó sẽ không tự xử lý một ngoại lệ, mà chuyển nó sang phương thức gọi.

Có từ khóa / thuộc tính tương tự trong C # không?

Nếu không có tương đương, làm thế nào bạn có thể đạt được hiệu quả tương tự (hoặc tương tự)?

Câu trả lời:


75

Trong Java, bạn phải xử lý một ngoại lệ hoặc đánh dấu phương thức là một phương thức có thể ném nó bằng throwstừ khóa.

C # không có từ khóa này hoặc từ khóa tương đương, như trong C #, nếu bạn không xử lý một ngoại lệ, nó sẽ nổi bong bóng, cho đến khi bắt được hoặc nếu không bắt được nó sẽ kết thúc chương trình.

Nếu bạn muốn xử lý nó sau đó ném lại bạn có thể làm như sau:

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

1
"it will bubble up", điều này có nghĩa là điều này tương đương với tất cả các phương thức có mệnh đề ném trong Java?
Louis Rhys

1
@Louis RH - loại. Nó có nghĩa là một ngoại lệ, nếu không được xử lý, sẽ đi lên chuỗi cuộc gọi thông qua mỗi chức năng gọi cho đến khi được xử lý.
Oded

1
@Louis RH không hoàn toàn, điều đó có nghĩa là bạn phải bắt được Ngoại lệ ít nhất trong Main của bạn để biên dịch mã. Vì C # không biết các ngoại lệ đã kiểm tra nên bạn có bắt chúng không, nếu không chúng sẽ hạ cánh trong thời gian chạy và làm gián đoạn mã của bạn.
Johannes Wachter

1
@jwatcher: một phương thức chính cũng có thể có mệnh đề ném.
Louis Rhys

4
@AshishKamble - ơ. Vấn đề quan điểm. Xử lý ngoại lệ khác nhau trong .NET. Đừng cho rằng bạn biết điều gì "tốt hơn".
Oded

105

Op đang hỏi về mệnh đề tương đương với C # của Javathrows - không phải throwtừ khóa. Điều này được sử dụng trong các chữ ký phương thức trong Java để chỉ ra một ngoại lệ đã kiểm tra có thể được ném ra.

Trong C #, không có tương đương trực tiếp với một ngoại lệ được kiểm tra trong Java. C # không có mệnh đề chữ ký phương thức tương đương.

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

Dịch sang

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

30

Vâng, đây là một chủ đề cũ, tuy nhiên tôi thường xuyên tìm thấy các chủ đề cũ khi tôi đang tìm kiếm câu trả lời trên googling, vì vậy tôi nghĩ rằng tôi sẽ thêm một cái gì đó hữu ích mà tôi đã tìm thấy.

Nếu bạn đang sử dụng Visual Studio 2012, có một công cụ tích hợp có thể được sử dụng để cho phép tương đương "ném" mức IDE.

Nếu bạn sử dụng Nhận xét của Tài liệu XML , như đã đề cập ở trên, thì bạn có thể sử dụng thẻ <exception> để chỉ định loại ngoại lệ được đưa ra bởi phương thức hoặc lớp cũng như thông tin về thời điểm hoặc lý do nó được ném.

thí dụ:

    /// <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, đây là câu trả lời của bạn. Tôi đoán, nhưng JAVA throwscó thể không có ý nghĩa gì đối với thời gian chạy, ngoài việc cung cấp thông tin cho nhà phát triển. Tương tự như vậy, điều mà @mvanella chỉ ra ở đây là cách làm của C # giống hệt như vậy. Tôi cho rằng bạn đã biết rằng "tài liệu xml" này có mục đích quan trọng hơn. Tôi biết chủ đề này đã cũ.
Hari Lubovac,

Trên thực tế, Java không tạo ra các ngoại lệ trừ khi nó được chỉ định rõ ràng trong một throwsmệnh đề hoặc được ném ra bởi một throwlệnh. Điều đó có nghĩa là nếu một RunTimeException xảy ra và không được xử lý trong cùng một phương thức mà nó xảy ra, thì việc thực thi sẽ dừng lại ở đó.
Pedro Lima

18

Đây là câu trả lời cho một câu hỏi tương tự mà tôi vừa tìm thấy trên bytes.com :

Câu trả lời ngắn gọn là không. Không có ngoại lệ nào được kiểm tra trong C #. Người thiết kế ngôn ngữ thảo luận về quyết định này trong cuộc phỏng vấn này:

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

Cách gần nhất bạn có thể nhận được là sử dụng các thẻ trong tài liệu XML của bạn và phân phối tài liệu được tạo NDoc với mã / hội đồng của bạn để người khác có thể xem bạn đưa ra ngoại lệ nào (chính xác là những gì MS làm trong tài liệu MSDN). Tuy nhiên, bạn không thể dựa vào trình biên dịch để cho bạn biết về các ngoại lệ không được xử lý, giống như bạn có thể đã quen với java.


7

Sau khi xem qua hầu hết các câu trả lời ở đây, tôi muốn thêm một vài suy nghĩ.

  1. Dựa vào Nhận xét của Tài liệu XML và mong đợi những người khác dựa vào là một lựa chọn sai lầm. Hầu hết mã C # mà tôi đã xem qua không ghi lại các phương pháp một cách hoàn chỉnh và nhất quán với Nhận xét của Tài liệu XML. Và sau đó, có một vấn đề lớn hơn là nếu không có các ngoại lệ được kiểm tra trong C #, làm thế nào bạn có thể ghi lại tất cả các ngoại lệ mà phương pháp của bạn ném ra nhằm mục đích cho người dùng API của bạn biết cách xử lý tất cả chúng một cách riêng lẻ? Hãy nhớ rằng, bạn chỉ biết về những thứ mà bạn tự ném vào với từ khóa ném trong quá trình triển khai của mình. Các API bạn đang sử dụng bên trong triển khai phương pháp của mình cũng có thể đưa ra các ngoại lệ mà bạn không biết vì chúng có thể không được ghi lại và bạn không xử lý chúng trong quá trình triển khai của mình, vì vậy chúng sẽ nổ tung khi đối mặt với người gọi của bạn phương pháp. Nói cách khác,

  2. Andreas đã liên kết một cuộc phỏng vấn với Anders Hejlsberg trong các câu trả lời ở đây về lý do tại sao nhóm thiết kế C # quyết định chống lại các ngoại lệ đã được kiểm tra. Câu trả lời cuối cùng cho câu hỏi ban đầu được ẩn trong cuộc phỏng vấn đó:

Các lập trình viên bảo vệ mã của họ bằng cách viết try cuối cùng ở khắp mọi nơi, vì vậy họ sẽ phản hồi chính xác nếu một ngoại lệ xảy ra, nhưng họ thực sự không quan tâm đến việc xử lý các ngoại lệ.

Nói cách khác, không ai nên quan tâm đến loại ngoại lệ nào có thể xảy ra đối với một API cụ thể vì bạn luôn bắt gặp tất cả chúng ở mọi nơi. Và nếu bạn muốn thực sự quan tâm đến các ngoại lệ cụ thể, cách xử lý chúng là tùy thuộc vào bạn chứ không phải ai đó xác định chữ ký phương thức bằng một thứ gì đó như từ khóa ném Java, buộc xử lý ngoại lệ cụ thể đối với người dùng API.

-

Riêng tôi, tôi bị xé rách ở đây. Tôi đồng ý với Anders rằng việc kiểm tra các ngoại lệ không giải quyết được vấn đề nếu không thêm các vấn đề mới, khác. Cũng giống như các nhận xét tài liệu XML, tôi hiếm khi thấy mã C # với mọi thứ được gói trong các khối try cuối cùng. Tôi cảm thấy rằng đây thực sự là lựa chọn duy nhất của bạn và một điều gì đó có vẻ như là một cách thực hành tốt.


3

Trên thực tế, việc không kiểm tra ngoại lệ trong C # có thể được coi là một điều tốt hoặc xấu.

Bản thân tôi coi đó là một giải pháp tốt vì các ngoại lệ được kiểm tra cung cấp cho bạn các vấn đề sau:

  1. Các trường hợp ngoại lệ kỹ thuật bị rò rỉ đến lớp doanh nghiệp / miền vì bạn không thể xử lý chúng đúng cách ở cấp thấp.
  2. Chúng thuộc về chữ ký phương thức không phải lúc nào cũng hoạt động tốt với thiết kế API.

Do đó, trong hầu hết các ứng dụng lớn hơn, bạn sẽ thấy mẫu sau thường xuyên khi được chọn Các ngoại lệ xảy ra:

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

Về cơ bản có nghĩa là mô phỏng cách C # /. NET xử lý tất cả các Ngoại lệ.


Tôi không thể tưởng tượng được làm thế nào các ngoại lệ đã kiểm tra sẽ kết hợp với lambdas!
Gabe

@Gabe: Tôi chắc rằng bạn có thể nghĩ ra một số khái niệm cho phép bạn kết hợp chúng, nhưng như tôi đã nói, các ngoại lệ được kiểm tra trong Java cũng hầu như không tốt, đặc biệt là trong các ứng dụng phức tạp hơn. Vì vậy, thật tốt khi họ không có ở đó trong C #.
Johannes Wachter

3

Bạn đang hỏi về điều này:

Bỏ lại một Ngoại lệ

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

hoặc là

static void Main() 
    {
        string s = null;

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

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

3
+1 để sử dụng throw. Bằng cách sử dụng nó, dấu vết ngăn xếp sẽ không bị mất.
Giuseppe Accaputo,

2

Có một số điểm tương đồng thoáng qua giữa .Net CodeContract EnsuresOnThrow<>và bộ throwsmô tả java , trong đó cả hai đều có thể báo hiệu cho người gọi là loại ngoại lệ có thể được tạo ra từ một hàm hoặc phương thức, mặc dù cũng có sự khác biệt lớn giữa 2:

  • EnsuresOnThrow<>không chỉ nêu rõ ngoại lệ nào có thể được ném, mà còn quy định các điều kiện mà chúng được đảm bảo sẽ được ném - đây có thể là đoạn mã khá rắc rối trong phương thức được gọi nếu điều kiện ngoại lệ không nhỏ để xác định. Java throwscung cấp một chỉ báo về những ngoại lệ nào có thể được ném ra (tức là IMO tiêu điểm trong .Net nằm bên trong phương thức hợp đồng để chứng minh throw, trong khi trong Java, tiêu điểm chuyển sang người gọi để thừa nhận khả năng xảy ra ngoại lệ).
  • .Net CC không phân biệt giữa các ngoại lệ Đã kiểm tra và Không kiểm tra mà Java có, mặc dù phần hướng dẫn sử dụng CC 2.2.2 có đề cập đến

"chỉ sử dụng các điều kiện hậu đặc biệt cho những trường hợp ngoại lệ mà người gọi phải mong đợi như một phần của API"

  • Trong .Net, người gọi có thể xác định xem có làm bất cứ điều gì với ngoại lệ hay không (ví dụ: bằng cách vô hiệu hợp đồng). Trong Java, người gọi phải làm điều gì đó , ngay cả khi nó thêm một throwsngoại lệ cho cùng một ngoại lệ trên giao diện của nó.

Hướng dẫn sử dụng Code Contracts tại đây


0

Nếu mục đích của phương thức c # là chỉ ném ra một ngoại lệ (như kiểu trả về js nói), tôi khuyên bạn chỉ nên trả về ngoại lệ đó. Xem ví dụ dưới đây:

    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;
    }

0

Đối với những người tự hỏi, bạn thậm chí không cần xác định những gì bạn nắm bắt để chuyển nó cho phương pháp tiếp theo. Trong trường hợp bạn muốn xử lý tất cả lỗi của mình trong một luồng chính, bạn có thể bắt mọi thứ và chuyển nó như vậy:

try {
    //your code here
}
catch {
    //this will throw any exceptions caught by this try/catch
    throw;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.