为什么抛出或捕获的类型必须从System.Exception派生

时间:2012-09-27 03:49:56

标签: c# .net exception compiler-errors

因此,出于好奇,我想看看异常类的特殊之处,它允许它与关键字Throw一起使用,而标准类则不然。

我发现只是Exception类实现了以下

public class Exception : System.Object, System.Runtime.Serialization.ISerializable, System.Runtime.InteropServices._Exception
{
}

所以我尝试实现那些相同的接口,并尝试抛出我自己的自定义异常,而不是从System.Exception派生而无济于事。我只是被告知

  

捕获或抛出的类型必须来自System.Exception

这有什么具体原因吗?我假设托管语言中的选择似乎很少是随意的。

6 个答案:

答案 0 :(得分:22)

我认为你的前提是错误的。抛出的对象可能不是从System.Exception派生的。你不能把它扔进C#或检查catch子句中的对象。从C#规范的第8.10节(v4.0):

  

某些编程语言可能支持非异常的异常   但可表示为从System.Exception派生的对象   C#代码永远不会产生这样的异常。一般的捕获   条款可用于捕获此类例外。因此,一般的抓住   子句在语义上与指定类型的子句不同   System.Exception,前者也可以捕获异常   其他语言。

一般性捕获的一个例子:

try
{
}
catch (Exception) { } // 'specific' catch
catch { } // 'general' catch

特别是,在调用非托管代码时这很重要。

有些类型似乎总是在每种语言中得到特殊待遇。主要是因为它们对系统非常重要。 System.ExceptionSystem.ValueTypeSystem.Delegate都是C#中与语言关键字和CLR紧密绑定的特殊类型,因此您不能只实现接管的类就不足为奇了他们的角色。

答案 1 :(得分:10)

Design Guidelines for Exceptions

  

例外是报告错误的标准机制。   应用程序和库不应使用返回代码进行通信   错误。异常的使用增加了一致的框架设计   并允许来自成员(例如构造函数)的错误报告   不能有返回类型

throw (C# Reference)

  

抛出的异常是一个派生自其类的对象   System.Exception,如以下示例所示。

class MyException : System.Exception {}
// ...
throw new MyException();

Exceptions Overview

  

在.NET Framework中,异常是继承自的对象   例外类

因此,您的例外情况必须来自System.Exception,但这取决于您,以及您如何组织它。

答案 2 :(得分:4)

该语言使用System.Exception作为所有例外的基础。这实际上意味着如果执行(Exception)myExc,任何可抛出或可捕获的异常都不应该出错。这可能是因为使用了System.Exception类的定义,因此所有异常都遵循相同的接口。由于接口一致,异常以堆栈跟踪和有意义的消息(例如)到达,这对于日志记录非常有用。

答案 3 :(得分:4)

这是CLS设计者的任意选择。据推测,他们出于一致性的原因做出了这一选择。 C#遵循CLS;出于这个原因,编译器强制执行该要求,而不是出于与Exception类型的实现相关的任何技术原因。

CLI实际上可以抛出任何对象。请参阅http://jilc.sourceforge.net/ecma_p3_cil.shtml#_Toc524462405

答案 4 :(得分:3)

每个异常都需要具有通用基类的一个原因是,您可以在单个catch块中捕获每种类型的异常。

如果我有这个:

try
{
    ...
}
catch(Exception ex)
{
    // Handle somehow
}

这将捕获所有异常,并允许我显示它是什么(使用ex.Message)。

如果你可以抛出任何东西,那么你将如何获得一个能够捕获所有东西但仍然可以访问抛出的对象的捕获?

你可以拥有它,它将完全捕获所有内容:

try
{
    ...
}
catch
{
    // Handle somehow
}

但是你已经'丢失了'扔掉的东西。

答案 5 :(得分:0)

我解决了添加“系统”作为参考

const useCallApi = async url => {
let instance = null;
let token = null;
  Promise.all([
    AsyncStorage.getItem('instance'),
    AsyncStorage.getItem('token')
  ]).then(d=>{
instance = d[0];
token = d[1];
}).catch(e=>throw e);
  const data = useFetch(`${instance}/api/v1/${url}`, {
    headers: {
      Authorization: `Bearer ${token}`
    }
  });
  return data;
};

export default useCallApi;