返回题库高级 .NET 刷题C# 选择题 · 第 19 / 50 篇

C# 试题 19:异常处理

0361 以下代码输出什么?

难度: 实战

try
{
    throw new InvalidOperationException("A");
}
catch (Exception ex) when (ex.Message == "B")
{
    Console.Write("filter");
}
catch (Exception)
{
    Console.Write("fallback");
}
  • A. filter
  • B. fallback,过滤器为 false 时继续匹配后续 catch
  • C. 抛异常
  • D. 什么都不输出
查看答案与解析

正确答案B

解析: when 过滤器为 false 时不进入该 catch,异常继续与后续 catch 子句匹配,最终落入兜底 catch 输出 fallback。过滤器是”匹配条件”,不是”进入后再判断”。

关键点: 过滤器 false 不会吞异常,会继续找下一个 catch。

0362 以下代码输出什么?

难度: 进阶

static bool Boom() => throw new Exception("filter boom");
try
{
    throw new Exception("original");
}
catch (Exception) when (Boom())
{
    Console.Write("caught");
}
catch (Exception)
{
    Console.Write("fallback");
}
  • A. caught
  • B. 抛 filter boom
  • C. fallback,过滤器求值中抛出的异常被忽略,视为 false
  • D. 抛 original
查看答案与解析

正确答案C

解析: 异常过滤器求值过程中抛出的异常会被运行时吞掉并当作 false 处理,不会向外传播;随后匹配到兜底 catch 输出 fallback。因此不要在过滤器里写可能抛异常的代码,异常会无声消失。

关键点: 过滤器内抛异常 = 被忽略 = 当作 false。

0363 关于以下两种重新抛出的写法,哪项正确?

难度: 实战

static void M()
{
    try
    {
        throw new InvalidOperationException("boom");
    }
    catch (Exception ex)
    {
        throw ex;   // ①
        // throw;   // ②
    }
}
  • A. 两者都保留原始堆栈
  • B. ① 重置堆栈(从 catch 内的 throw 重新开始),② 保留原始堆栈
  • C. ① 保留原始堆栈,② 重置堆栈
  • D. 两者都重置堆栈
查看答案与解析

正确答案B

解析: throw ex 抛出的是同一个异常对象,但堆栈跟踪会被重置为”从当前 throw 语句开始”,丢失原始抛出点;throw;(裸 rethrow)不创建新跟踪,完整保留原始堆栈与内部异常链。日志分析时 throw ex 是经典的误导源。

关键点: 重新抛出用 throw;throw ex 会毁掉堆栈跟踪。

0364 以下代码输出什么?

难度: 实战

try
{
    try
    {
        throw new InvalidOperationException("inner");
    }
    catch (Exception ex)
    {
        throw new ApplicationException("wrap", ex);
    }
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
    Console.WriteLine(ex.InnerException?.GetType().Name);
}
  • A. innerApplicationException
  • B. wrapApplicationException
  • C. wrapInvalidOperationException,包装异常通过 InnerException 保留原始异常
  • D. 编译失败
查看答案与解析

正确答案C

解析: 内层 catch 用 new ApplicationException("wrap", ex) 包装,外层拿到的是包装异常:MessagewrapInnerException 是原来的 InvalidOperationException。包装语义是”保留原因、替换表象”,排查问题时必须沿 InnerException 链下钻。

关键点: 包装异常不丢原始异常,原始异常在 InnerException 里。

0365 以下代码运行结果是什么?

难度: 进阶

try
{
    throw new InvalidOperationException("original");
}
finally
{
    throw new FormatException("finally");
}
  • A. 抛 InvalidOperationException
  • B. 同时抛两个异常
  • C. 编译失败
  • D. 抛 FormatException,finally 中抛出的异常覆盖正在传播的原始异常
查看答案与解析

正确答案D

解析: 异常传播途中执行 finally 时,若 finally 又抛出异常,后者的传播优先级更高,原始异常直接丢失(不会合并为 AggregateException)。finally 里抛异常是”吞掉原异常”的高危行为,应避免或就地 try/catch。

关键点: finally 抛异常会覆盖原始异常,原始异常信息丢失。

0366 为什么不应把异常用于正常的控制流?

难度: 进阶

  • A. 异常用于预期分支会带来不必要的栈展开开销、干扰调试与日志,并掩盖真实语义
  • B. 异常与 return 性能完全相同
  • C. 异常只能用于 I/O 场景
  • D. try/catch 必须捕获所有异常
查看答案与解析

正确答案A

解析: 异常是为”异常情况”设计的:抛出涉及栈展开、SEH 记录与堆栈跟踪构造,成本远高于分支判断;把”用户输入非法”等预期情况做成异常,会让调用方语义不清、调试器频繁中断。预期分支应走 TryXxx/结果类型等正常路径。

关键点: 异常开销在抛出路径,且用异常表达预期分支是反模式。

0367 以下代码能否编译?

难度: 实战

try
{
    throw new FormatException();
}
catch (Exception)
{
    Console.Write("base");
}
catch (FormatException)
{
    Console.Write("derived");
}
  • A. 编译通过,输出 base
  • B. 编译失败,派生类型的 catch 必须放在基类 catch 之前
  • C. 编译通过,输出 derived
  • D. 编译通过,输出 basederived
查看答案与解析

正确答案B

解析: catch (Exception) 能匹配所有异常,后面的 catch (FormatException) 永远不可达,编译器报 CS0160。catch 子句按顺序匹配,派生类型在前、基类在后是硬性要求;先写基类 catch 是编译错误而不是运行时行为。

关键点: catch 顺序:具体在前、基类在后,否则编译失败。

0368 关于自定义异常类型,哪项实践正确?

难度: 进阶

  • A. 应继承 ApplicationException
  • B. 任何类型都可以作为异常抛出
  • C. 直接继承 Exception(或语义更具体的异常类),类名以 Exception 结尾,并提供常见构造函数
  • D. 自定义异常不能包含自定义属性
查看答案与解析

正确答案C

解析: 早期指南建议用 ApplicationException 作为基类,该建议早已废弃,自定义异常应直接继承 Exception 或更具体的异常;类名以 Exception 结尾便于识别;提供无参、message、message+inner 等构造函数是惯例。C# 只允许抛出 Exception 派生类型。

关键点: 基类用 Exception,别再用 ApplicationException 旧建议。

0369 以下代码输出什么?

难度: 实战

class BaseException : Exception { }
class DerivedException : BaseException { }
try
{
    throw new DerivedException();
}
catch (BaseException)
{
    Console.Write("base");
}
catch (DerivedException)
{
    Console.Write("derived");
}
  • A. derived
  • B. basederived
  • C. 编译失败
  • D. base,第一个能处理该异常的 catch 生效
查看答案与解析

正确答案D

解析: catch 匹配是”第一个能处理”而非”最精确”:DerivedExceptionBaseException 的子类,先出现的 catch (BaseException) 直接捕获,后面的 catch (DerivedException) 永远轮不到(此处未报错是因为派生 catch 顺序合法但不可达)。这与某些语言的”最近匹配”直觉相反。

关键点: catch 按书写顺序取第一个能处理的,不取最具体的。

0370 以下代码输出什么?

难度: 进阶

class R : IDisposable
{
    public void Dispose() => throw new FormatException("dispose");
}
try
{
    using var r = new R();
    throw new InvalidOperationException("body");
}
catch (Exception ex)
{
    Console.WriteLine(ex.GetType().Name);
}
  • A. FormatException,using 展开为 try/finally,Dispose 的异常覆盖 try 块异常
  • B. InvalidOperationException
  • C. AggregateException
  • D. ObjectDisposedException
查看答案与解析

正确答案A

解析: using 等价于 try/finally 中调用 Dispose();try 块异常传播途中 finally 里 Dispose 又抛异常,后者覆盖前者,catch 拿到 FormatException。这正是”Dispose 不应抛异常”原则的由来——它会让业务异常消失。

关键点: Dispose 抛异常会吞掉 try 块的原始异常。

0371 以下代码输出什么?

难度: 实战

static int M()
{
    try
    {
        return 1;
    }
    finally
    {
        Console.Write("f");
    }
}
Console.WriteLine(M());
  • A. 1f
  • B. 1
  • C. f1,finally 在返回值生效前执行
  • D. 编译失败
查看答案与解析

正确答案C

解析: 方法返回前必须先执行 finally:先输出 f,再返回 1 由外层输出,结果 f1。finally 的执行时机是”退出 try 块之前”,包括 return 路径,这是”finally 一定执行”的语义基础(进程终止等极端情况除外)。

关键点: return 之前 finally 先跑,别假设 finally 在返回值之后。

0372 以下代码输出什么?

难度: 进阶

static int M()
{
    try
    {
        throw new Exception();
    }
    catch
    {
        return 2;
    }
    finally
    {
        Console.Write("f");
    }
}
Console.WriteLine(M());
  • A. f2,catch 中 return 同样先执行 finally
  • B. 2f
  • C. 2
  • D. 编译失败
查看答案与解析

正确答案A

解析: catch 里的 return 2 也会先触发 finally:输出 f 后方法返回 2,外层输出,结果 f2。finally 覆盖 try/catch 的所有退出路径(return、throw、正常结束)。

关键点: finally 对 return 与 throw 一视同仁,先清理后返回。

0373 以下代码能否编译?

难度: 实战

static int M()
{
    try { }
    finally
    {
        return 1;
    }
}
  • A. 编译通过,返回 1
  • B. 编译通过,运行抛异常
  • C. 编译通过,返回 0
  • D. 编译失败,控制流不能从 finally 块中离开
查看答案与解析

正确答案D

解析: return(以及 break/continue/goto)在 finally 中是被禁止的,报 CS0157——它会吞掉尚未传播的异常并破坏清理语义。finally 里只能做清理,结果值必须在 try/catch 里决定。

关键点: finally 中不能 return,这是编译期规则。

0374 以下代码输出什么?

难度: 实战

public class OrderException : Exception
{
    public int OrderId { get; }
    public OrderException(int orderId)
        : base($"Order {orderId} failed") => OrderId = orderId;
}
try
{
    throw new OrderException(42);
}
catch (OrderException ex)
{
    Console.WriteLine(ex.OrderId);
    Console.WriteLine(ex.Message);
}
  • A. 0Exception of type 'OrderException' was thrown.
  • B. 42Order 42 failed
  • C. 编译失败
  • D. 42Order failed
查看答案与解析

正确答案B

解析: 自定义异常通过构造函数链把业务数据写入属性、把可读信息写入 Message:抛出 OrderException(42) 后,OrderId 为 42,MessageOrder 42 failed。业务上下文应存在异常对象自身,而不是让调用方去猜。

关键点: 自定义异常用属性携带上下文,用 Message 提供可读信息。

0375 以下代码输出什么?

难度: 进阶

try
{
    try
    {
        throw new InvalidOperationException("x");
    }
    catch (Exception) when (false)
    {
        Console.Write("filtered");
    }
}
catch (Exception ex)
{
    Console.Write(ex.GetType().Name);
}
  • A. InvalidOperationException,过滤器为 false 时异常继续向外传播
  • B. filtered
  • C. Exception
  • D. 什么都不输出
查看答案与解析

正确答案A

解析: 内层 catch 的过滤器恒为 false,等于”这个 catch 不存在”,异常继续向上传播,被外层 catch 捕获,输出异常类型名 InvalidOperationException。过滤器 false 不吞异常——吞掉异常的只能是真正进入的 catch 块。

关键点: 过滤器 false = 该 catch 不匹配,异常继续传播。

0376 关于异常的性能开销,哪项正确?

难度: 进阶

  • A. try/catch 块本身开销巨大,应尽量避免使用
  • B. 未抛异常时 try/catch 几乎零成本;昂贵的是抛出、栈展开与堆栈跟踪构造
  • C. 异常抛出后会被自动压缩
  • D. 异常对象总是分配在栈上
查看答案与解析

正确答案B

解析: 现代 .NET 中,进入/退出 try 块在未抛异常时几乎没有运行时开销(异常表在 JIT 侧处理);真正的成本集中在 throw 之后的栈展开与 StackTrace 构造。因此”try 要省着用”不准确,该省的是”抛”本身。

关键点: 贵在抛不在 try;高频预期路径用 TryXxx 避免抛。

0377 以下代码输出什么?

难度: 实战

class R : IDisposable
{
    public R(string name) => Name = name;
    public string Name { get; }
    public void Dispose() => Console.Write(Name);
}
using var a = new R("a");
using var b = new R("b");
  • A. ab
  • B. 编译失败
  • C. ba,using 声明按相反顺序释放
  • D. 什么都不输出
查看答案与解析

正确答案C

解析: 多个 using 声明按”后进先出”释放:b 先 Dispose,再 a,输出 ba。这与嵌套 using 语句块的语义一致。依赖释放顺序时(如日志、锁),这个方向最容易记反。

关键点: 多 using 声明的释放顺序与声明顺序相反。

0378 以下代码运行结果是什么?

难度: 实战

class R : IDisposable
{
    private bool _disposed;
    public void DoWork()
    {
        if (_disposed) throw new ObjectDisposedException(nameof(R));
        Console.Write("work");
    }
    public void Dispose() => _disposed = true;
}
var r = new R();
using (r)
{
}
r.DoWork();
  • A. 输出 work
  • B. 编译失败,using 后的变量不可用
  • C. 运行抛 NullReferenceException
  • D. 运行抛 ObjectDisposedException,using 只负责释放,不禁止块外继续使用变量
查看答案与解析

正确答案D

解析: using (r) 结束后 r 仍然可访问——using 只是在 finally 里调用 Dispose(),不改变变量作用域;再次 DoWork() 由类型自己的已释放检查抛 ObjectDisposedException。“using 之后的变量不可用”是错误直觉,资源已释放但引用还在。

关键点: using 释放资源但不禁用变量;释放后调用由对象自检抛异常。

0379 以下代码输出什么?

难度: 进阶

static Task Boom()
{
    return Task.Run(() => throw new InvalidOperationException("x"));
}
try
{
    Boom().Wait();
}
catch (Exception ex)
{
    Console.Write(ex.GetType().Name);
}
  • A. AggregateException,同步等待失败的任务会把异常包装起来
  • B. InvalidOperationException
  • C. TaskCanceledException
  • D. 编译失败
查看答案与解析

正确答案A

解析: Task.Wait() 对失败任务抛的是 AggregateException(内含原始异常);只有 await 才会解包出第一个原始异常。所以”任务异常 = 原异常”的直觉只对 await 成立,同步 Wait()/Result 一律先看到 AggregateException

关键点: Wait/Result 抛 AggregateException,await 才解包。

0380 以下代码输出什么?

难度: 实战

static void M()
{
    try
    {
        try
        {
            throw new InvalidOperationException("x");
        }
        finally
        {
            Console.Write("inner-finally;");
        }
    }
    catch (Exception) when (true)
    {
        Console.Write("caught;");
    }
    finally
    {
        Console.Write("outer-finally;");
    }
}
M();
  • A. caught;inner-finally;outer-finally;
  • B. inner-finally;caught;outer-finally;,异常展开时先执行内层 finally,再匹配外层 catch,最后执行外层 finally
  • C. inner-finally;outer-finally;caught;
  • D. 编译失败
查看答案与解析

正确答案B

解析: 内层 throw 后:① 展开途中先执行内层 finally(inner-finally;);② 异常到达外层,求值过滤器并进入 catch(caught;);③ 退出 try 前执行外层 finally(outer-finally;)。finally 在栈展开时按”由内到外”执行,catch 匹配发生在每层 finally 之后。

关键点: 展开顺序:内层 finally → 外层 catch → 外层 finally。

官方资料

当前分类

C# 选择题

查看全部分类 →
  1. 17C# 试题 17:委托与 Lambda20 题
  2. 18C# 试题 18:事件20 题
  3. 19C# 试题 19:异常处理20 题
  4. 20C# 试题 20:数组、Index 与 Range20 题
  5. 21C# 试题 21:Span 与 Memory20 题
ESC

输入关键词开始搜索