与" 如何在C++中实现异常(在幕后) "相同,但对于C#.
我知道抛出异常时必须执行以下步骤.
finally
块..NET如何处理这些操作?"当前"处理程序的映射如何工作?try/catch块中发出了多少代码?在一个扔石块?
我有一个问题:如何抛出异常并退出程序?我写了一个简单的例子:
-- main.hs
import Test
main = do
Test.foo ""
putStrLn "make some other things"
Run Code Online (Sandbox Code Playgroud)
这是模块:
moldule Test where
foo :: String -> IO ()
foo x = do
if null x
then THROW EXCEPTION AND EXIT MAIN else putStrLn "okay"
Run Code Online (Sandbox Code Playgroud)
我想启动它并抛出异常并退出程序,但是如何?
在Java(目前使用Java 8)中,我可以编写这个并且所有编译都很好:
Supplier<Long> asd = () -> {
throw new RuntimeException();
};
Run Code Online (Sandbox Code Playgroud)
但是,我不能这样写:
Supplier<Long> asd = () -> throw new RuntimeException(); // This won't compile :(
Run Code Online (Sandbox Code Playgroud)
有谁知道为什么Java的实现不允许这样的样式(表达式lambda)和只有语句/代码块样式lambda?
我的意思是,由于lambda 只抛出RuntimeException,为什么JDK不能将lambda表达式推断为:
new Supplier<Long>() {
@Override
public Long get() {
throw new RuntimeException();
}
};
Run Code Online (Sandbox Code Playgroud)
这是在specs/docs中的某处记录的吗?这是仅在JDK> 8中添加的吗?
当您需要抛出未在您正在实现的接口中定义的异常时,要遵循的最佳实践是什么?
这是一个例子:
public interface Reader
{
public abstract void read() throws IOException;
}
public class CarrotReader implements Reader
{
public void read() throws IOException {}
}
public class CupcakeReader implements Reader
{
public void read() throws IOException, CupcakeException {}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您在阅读纸杯蛋糕时会发生特定的异常,因此您希望抛出与此相关的异常.但是,Reader没有在其界面中定义此类异常,那么您如何做?此外,将CupcakeException添加到Reader接口中的throws子句没有意义,因为这种类型的异常特定于CupcakeReader.解决这个问题的一种方法是让Reader定义read,使其抛出一些父类型,如Exception,但是你会丢失异常的上下文.在这种情况下你应该怎么做?谢谢!
已经提出的另一个有趣的情况涉及一个你无法控制的界面.在这种情况下,表明问题发生的最佳方法是什么?
为了便于说明,这是另一个例子:
public interface Reader
{
public abstract void read();
}
public class CupcakeReader implements Reader
{
public void read() throws CupcakeException {} …
Run Code Online (Sandbox Code Playgroud) 我偶然注意到这个throw
语句(从一些更复杂的代码中提取)编译:
void foo() {
try {
} catch (Throwable t) {
throw t;
}
}
Run Code Online (Sandbox Code Playgroud)
对于一个短暂而快乐的时刻,我认为已经检查过的异常最终决定已经死了,但它仍然在这方面很高兴:
void foo() {
try {
} catch (Throwable t) {
Throwable t1 = t;
throw t1;
}
}
Run Code Online (Sandbox Code Playgroud)
该try
块不必为空; 它似乎可以有代码,只要该代码不会抛出已检查的异常.这似乎是合理的,但我的问题是,语言规范中的哪些规则描述了这种行为?据我所知,§14.18town语句明确禁止它,因为t
表达式的类型是一个已检查的异常,并且它没有被捕获或声明被抛出.(?)
什么时候使用ThrowHelper方法而不是直接投掷?
void MyMethod() {
...
//throw new ArgumentNullException("paramName");
ThrowArgumentNullException("paramName");
...
}
void ThrowArgumentNullException(string paramName) {
throw new ArgumentNullException(paramName);
}
Run Code Online (Sandbox Code Playgroud)
我已经读过调用一个ThrowHelper方法(一个抛出异常的唯一方法)而不是直接抛出应该产生更小的字节码.
这个以及明显的封装(另一层间接)可能是不直接抛出的好理由,至少在某些情况下是这样.
无论如何,IMO的缺点也不是没有实质性的.
我有限的经验是整体设计经常变得更糟.
int MyMethod(int i) {
switch (i) {
case 1:
return 1;
default:
ThrowMyException();
}
return 0; // Unreachable (but needed) code
}
Run Code Online (Sandbox Code Playgroud)
这可能部分是个人品味的问题.无论如何,你对这个问题有什么个人指导?您是否发现将ThrowHelpers用于所有常见任务(如方法参数验证(ThrowArgumentNullException(paramName)等)是个好主意?我在这个问题上遗漏了哪些明显的东西?
顺便说一下,我试图不将此问题与验证问题混在一起,例如:
ThrowIfNameIsNullOrEmpty(name);
Run Code Online (Sandbox Code Playgroud) 使用Google Mock 1.7.0,我有一个带有方法的模拟对象,我希望它被调用,在这种情况下,模拟的方法应该抛出异常.
ObjectMock object_mock_;
EXPECT_CALL(object_mock_, method())
.Times(1)
.WillRepeatedly(???);
Run Code Online (Sandbox Code Playgroud)
是否存在引发异常的Google Mock操作?我没有在文档中找到它,但我怀疑到目前为止还没有人需要它.
谢谢!
来自C++ Primer 18.1.1:
如果[thrown]表达式具有数组或函数类型,则表达式将转换为其对应的指针类型.
该程序如何产生9876543210
(g ++ 5.2.0)的正确输出?
#include <iostream>
using namespace std;
int main(){
try{
int a[10] = {9,8,7,6,5,4,3,2,1,0};
throw a;
}
catch(int* b) { for(int i = 0; i < 10; ++i) cout << *(b+i); }
}
Run Code Online (Sandbox Code Playgroud)
从引用中,throw a
将创建一个类型的异常对象,int*
它是指向数组的第一个元素的指针.但是a
当我们退出try
块并输入catch子句时,我们肯定会破坏数组元素,因为我们改变了块范围?在catch子句的持续时间内,我是否得到了误报或数组元素"单独留下"(未删除)?
我知道这可能并不重要,但我想知道什么是正确的.
如果一段代码包含某些版本的throw new SomeKindOfException()
.我们是否说这段代码可能引发异常?或抛出异常?
关键字是throw
,所以我倾向于那个,但提出异常也被大量使用...
他们有某种不同的含义吗?他们中的一个是否与另一个有所不同?或者它只是两个词意味着完全相同的东西?
考虑片段:
try {
Foo f;
throw std::move(f);
}
catch (Foo& f) { }
Run Code Online (Sandbox Code Playgroud)
[expr.throw]说:
异常对象的类型是通过从操作数的静态类型中删除任何顶级cv限定符并将类型从"T的数组"或"返回T的函数"调整为"指向T的指针"或"指针"来确定的.函数返回T",分别.
这将是Foo&&
.然后根据[except.throw]初始化异常对象:
抛出异常copy-initializes(8.5,12.8)一个临时对象,称为异常对象.临时是一个左值,用于初始化匹配处理程序中声明的变量(15.3).如果异常对象的类型是不完整类型或指向不完整类型的指针(可能是cv-qualified),
void
则程序格式不正确.
这告诉我异常对象被初始化为:
Foo&& __exception_object = std::move(f);
Run Code Online (Sandbox Code Playgroud)
并且处理程序不匹配.但是,gcc和clang都会捕获此异常.那么这里的异常对象的实际类型是什么?如果Foo
,为什么?