How to use Java-style throws keyword in C#?

In Java, the throws keyword allows for a method to declare that it will not handle an exception on its own, but rather throw it to the calling method.

Is there a similar keyword/attribute in C#?

If there is no equivalent, how can you accomplish the same (or a similar) effect?

75327 次浏览

在 Java 中,必须处理异常,或者将方法标记为可能使用 throws关键字抛出异常的方法。

C # 没有这个关键字或者等价的关键字,就像 C # 一样,如果你不处理异常,它就会冒泡,直到被捕获或者没有被捕获,它就会终止程序。

如果你想处理它,然后重新抛出,你可以做到以下几点:

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

你问的是这个:

重新引发异常

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
}

下面是我在 bytes.com上发现的一个类似问题的答案:

简短的回答是否定的。 C # 中没有检查过的异常 语言设计师在这次采访中讨论了这个决定:

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

最接近的方法是使用 XML 中的标记 文档,并将 NDoc 生成的文档与您的 代码/程序集,以便其他人可以看到您引发的异常 (这正是 MS 在 MSDN 文档中所做的) 在编译器上告诉您有关未处理的异常,但是,像 你可能在爪哇已经习惯了。

实际上,在 C # 中没有检查异常可以被认为是一件好事或一件坏事。

I myself consider it to be a good solution since checked exceptions provide you with the following problems:

  1. 技术异常泄漏到业务/域层,因为您不能在低层正确地处理它们。
  2. 它们属于方法签名,这种方法签名并不总是适合 API 设计。

因此,在大多数较大的应用程序中,当选中的异常出现时,您会经常看到以下模式:

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

这实际上意味着模拟 C #/. NET 处理所有异常的方式。

The op is asking about the C # 相当于 Java 的 throws子句 - not the throw keyword. This is used in method signatures in Java to indicate a checked exception can be thrown.

在 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...
}

是的,这是一个老线程,但是我经常发现旧线程时,我谷歌答案,所以我想我会添加一些有用的东西,我已经找到了。

如果您使用的是 VisualStudio2012,则可以使用一个内置工具来支持 IDE 级别的“抛出”等效项。

如果您使用上面提到的 XML 文档注释,那么您可以使用 < 例外 > 标记来指定方法或类引发的异常的类型,以及关于何时或为什么引发异常的信息。

例如:

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

两者之间有一些稍纵即逝的相似之处。Net CodeContractEnsuresOnThrow<>和 java throws描述符,因为两者都可以向调用者发出信号,作为可以从函数或方法引发的异常类型,尽管两者之间也有很大的区别:

  • EnsuresOnThrow<>不仅仅说明可以抛出哪些异常,还规定了保证抛出异常的条件——如果异常条件不容易识别,那么在被调用的方法中这可能是相当繁琐的代码。Javathrows提供了可抛出哪些异常的指示(例如,。Net 在证明 throw的契约方法中,而在 Java 中,焦点转移到调用方以确认异常的可能性)。
  • .Net CC doesn't make the distinction between 检查和未检查 exceptions that Java has, although the CC manual section 2.2.2 does mention to

”仅对调用方 应该作为空气污染指数的一部分

  • 进去。Net 调用者可以决定是否对异常执行任何操作(例如通过禁用合同)。在 Java 中,调用方 必须做点什么,即使它在其接口上为相同的异常添加了 throws

这里是代码合同手册

在浏览了这里的大部分答案之后,我想补充一些想法。

  1. 依赖 XML 文档注释并期望其他人依赖是一个糟糕的选择。我遇到的大多数 C # 代码都没有完全和一致地使用 XML 文档注释对方法进行文档化。然后还有一个更大的问题,在 C # 中没有检查异常,你如何记录你的方法抛出的所有异常,让你的 API 用户知道如何单独处理它们?请记住,您只知道在您的实现中使用 throw 关键字抛出的关键字。您在方法实现中使用的 API 也可能抛出您不知道的异常,因为它们可能没有文档化,而且您在实现中没有处理它们,所以它们会在方法的调用者面前爆炸。换句话说,这些 XML 文档注释不能替代已检查的异常。

  2. Andreas 将采访与安德斯·海尔斯伯格联系起来,在这里回答为什么 C # 设计团队决定不检查异常。对最初问题的最终回答隐藏在采访中:

程序员通过在各处编写 try finally 来保护他们的代码,所以如果发生异常,他们会正确地退出,但是他们实际上对处理异常并不感兴趣。

换句话说,没有人应该对特定 API 可能出现的异常类型感兴趣,因为您总是会在任何地方捕获所有这些异常。如果您真的想关心特定的异常,那么如何处理它们取决于您,而不是由某人使用类似 Java throw 关键字之类的东西定义方法签名,从而强制 API 用户进行特定的异常处理。

--

就我个人而言,我很纠结。我同意 Anders 的观点,即检查异常并不能在不添加新的、不同的问题的情况下解决问题。就像 XML 文档注释一样,我很少看到 C # 代码将所有内容都包装在 try finally 块中。在我看来,这确实是你唯一的选择,也是一个不错的练习。

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


对于那些想知道的人,您甚至不需要定义捕获的内容来将其传递给下一个方法。如果你想在一个主线程中处理所有的错误,你可以捕获所有的错误,然后像这样传递:

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