C# 7 中 "throw" 表达式的编译时类型是什么?
What is the compile-time type of the "throw" expression in C# 7?
在 C# 7 中,可以在表达式中引发异常:
int n = list != null ? list.Count : throw new NullReferenceException("list");
在这个位置,throw表达式可以替换任何类型的表达式。
现在我想定义一个在引发异常之前执行某些操作的函数:
??? DoSomethingAndThrowException(Exception e)
{
MessageBox.Show("Prepare for an exception!");
throw e;
}
这种函数的 return 类型是什么,以便它可以在与原始 throw 表达式相同的地方使用:
int n = list != null ? list.Count : DoSomethingAndThrowException(new NullReferenceException("list"));
可以选择将其声明为通用方法:
T DoSomethingAndThrowException<T>(Exception e) {...}
但这看起来很麻烦,因为泛型类型不会出现在函数体的任何地方。这是唯一的方法吗,还是有一些我不知道的类型,并且可以分配给任何类型("anti-object" 类型,可以这么说)?
您所说的类型称为 the bottom type, the subtype of all types, as opposed to the top type,所有类型的超类型。
如您所述,C# 中的顶级类型称为 object
*。另一方面,C#没有底层类型(虽然有a proposal to add it)。
虽然实际上有一种类型可以隐式转换为任何其他类型:dynamic
。这意味着如果您将 DoSomethingAndThrowException
的 return 类型设置为 dynamic
,您的代码将编译。但是我觉得dynamic
在这里不是一个好的选择,因为它太有感染力了。例如,如果您在语句 (var n = list != null ? list.Count : DoSomethingAndThrowException(new NullReferenceException("list"));
) 中使用了 var
,那么 n
的类型将是 dynamic
,以及带来的所有包袱。
我认为这意味着您的结论是正确的:泛型是您的最佳选择。
* 从技术上讲,object
不是顶级类型,因为 object
不是指针类型的超类型。但我认为这是一个无关紧要的区别。
除非两个表达式 return 类型相同或存在从一种类型到另一种类型的转换,否则三元运算符不会编译。所以 throw
表达式的类型是什么并不重要。除非 DoSomethingAndThrowException
returns int
或可以隐式转换为 int
的东西,否则它不会编译。
三元运算符只是为了方便,shorthand是为了if
语句。但是在这种情况下显然不方便,所以使用它或在其他地方编写额外的代码以便您可以使用它没有任何好处。
这样会更清楚:
int n;
if(list!=null)
n = list.Count;
else
DoSomethingAndThrowException(new NullReferenceException("list"));
更好的是,
if(list==null) DoSomethingAndThrowException(new NullReferenceException("list"));
var n = list.Count;
这样就更明确了:
if(list==null)
{
DoSomething();
throw new NullReferenceException("list");
}
var n = list.Count();
这可能看起来像是在吹毛求疵,但在这种情况下,遵循典型的惯例通常比做一些以同样的方式工作的有创意的东西要好。执行是一样的,但是稍后阅读代码的人可能会多花十秒钟来弄清楚发生了什么。
有一种解决方案可以让您保持自己的模式。唯一的变化是你抛出你的方法,而不是抛出方法内部。不要想太多!
private static Exception DoSomethingAndReturnException(Exception exception)
{
// Do something
// in the end, return the exception
return exception;
}
你可以这样使用它:
int n = (list != null) ? list.Count : throw DoSomethingAndReturnException(new NullReferenceException("list"));
这是简短的specification for the throw-expression feature。
您问题的相关部分:
The type rules are as follows:
- A throw_expression has no type.
- A throw_expression is convertible to every type by an implicit conversion.
在 C# 7 中,可以在表达式中引发异常:
int n = list != null ? list.Count : throw new NullReferenceException("list");
在这个位置,throw表达式可以替换任何类型的表达式。
现在我想定义一个在引发异常之前执行某些操作的函数:
??? DoSomethingAndThrowException(Exception e)
{
MessageBox.Show("Prepare for an exception!");
throw e;
}
这种函数的 return 类型是什么,以便它可以在与原始 throw 表达式相同的地方使用:
int n = list != null ? list.Count : DoSomethingAndThrowException(new NullReferenceException("list"));
可以选择将其声明为通用方法:
T DoSomethingAndThrowException<T>(Exception e) {...}
但这看起来很麻烦,因为泛型类型不会出现在函数体的任何地方。这是唯一的方法吗,还是有一些我不知道的类型,并且可以分配给任何类型("anti-object" 类型,可以这么说)?
您所说的类型称为 the bottom type, the subtype of all types, as opposed to the top type,所有类型的超类型。
如您所述,C# 中的顶级类型称为 object
*。另一方面,C#没有底层类型(虽然有a proposal to add it)。
虽然实际上有一种类型可以隐式转换为任何其他类型:dynamic
。这意味着如果您将 DoSomethingAndThrowException
的 return 类型设置为 dynamic
,您的代码将编译。但是我觉得dynamic
在这里不是一个好的选择,因为它太有感染力了。例如,如果您在语句 (var n = list != null ? list.Count : DoSomethingAndThrowException(new NullReferenceException("list"));
) 中使用了 var
,那么 n
的类型将是 dynamic
,以及带来的所有包袱。
我认为这意味着您的结论是正确的:泛型是您的最佳选择。
* 从技术上讲,object
不是顶级类型,因为 object
不是指针类型的超类型。但我认为这是一个无关紧要的区别。
除非两个表达式 return 类型相同或存在从一种类型到另一种类型的转换,否则三元运算符不会编译。所以 throw
表达式的类型是什么并不重要。除非 DoSomethingAndThrowException
returns int
或可以隐式转换为 int
的东西,否则它不会编译。
三元运算符只是为了方便,shorthand是为了if
语句。但是在这种情况下显然不方便,所以使用它或在其他地方编写额外的代码以便您可以使用它没有任何好处。
这样会更清楚:
int n;
if(list!=null)
n = list.Count;
else
DoSomethingAndThrowException(new NullReferenceException("list"));
更好的是,
if(list==null) DoSomethingAndThrowException(new NullReferenceException("list"));
var n = list.Count;
这样就更明确了:
if(list==null)
{
DoSomething();
throw new NullReferenceException("list");
}
var n = list.Count();
这可能看起来像是在吹毛求疵,但在这种情况下,遵循典型的惯例通常比做一些以同样的方式工作的有创意的东西要好。执行是一样的,但是稍后阅读代码的人可能会多花十秒钟来弄清楚发生了什么。
有一种解决方案可以让您保持自己的模式。唯一的变化是你抛出你的方法,而不是抛出方法内部。不要想太多!
private static Exception DoSomethingAndReturnException(Exception exception)
{
// Do something
// in the end, return the exception
return exception;
}
你可以这样使用它:
int n = (list != null) ? list.Count : throw DoSomethingAndReturnException(new NullReferenceException("list"));
这是简短的specification for the throw-expression feature。
您问题的相关部分:
The type rules are as follows:
- A throw_expression has no type.
- A throw_expression is convertible to every type by an implicit conversion.