C#中断言失败时如何抛出异常?是否有内置等效方法?
问题描述
我最近开始在代码里用断言,但发现Debug.Assert和Trace.Assert在条件不满足的时候还会继续执行代码。我想找一个内置的等效方法,能在条件不满足时直接抛出异常,这样就能避免代码在意外状态下继续跑了,还是说我得自己实现这个逻辑?
编辑补充:我的代码大概是这样的,这段代码用于处理PUT请求,目的是更新现有资源(理想情况下用Id标识,如果之前有部分保存的情况就用GUID标识)。如果是保存新资源,必须确保提供了GUID:
public int Save(Guid? personGuid, Person person) { if (person.Id > 0) { Update(person); } Trace.Assert(personGuid.HasValue); SaveToDb(personGuid, person); }
注:已经勾选了Define TRACE常量选项。
解决方案
其实.NET里没有直接开箱即用的“断言失败就抛异常”的方法——毕竟Debug.Assert和Trace.Assert的设计初衷是调试时给出提示,而非直接终止执行抛出异常。不过有几种简单的方案可以实现你要的效果,根据你的场景选就行:
1. 自己写个轻量的断言工具类(最推荐,灵活可控)
这其实花不了几分钟,写个静态类就能搞定,还能完全控制异常类型、错误信息,甚至可以指定只在Debug模式生效:
public static class MyAssert { // 加[Conditional("DEBUG")]就只在Debug模式下触发,去掉的话Release也会生效 [Conditional("DEBUG")] public static void IsTrue(bool condition, string errorMessage = "断言失败:不符合预期状态") { if (!condition) { // 这里可以根据业务场景换更合适的异常类型,比如ArgumentException、InvalidOperationException等 throw new InvalidOperationException(errorMessage); } } }
然后你的代码改成这样就行:
public int Save(Guid? personGuid, Person person) { if (person.Id > 0) { Update(person); } MyAssert.IsTrue(personGuid.HasValue, "保存新资源时必须提供有效的GUID"); SaveToDb(personGuid, person); }
这个方案的好处是完全贴合你的需求,而且可以根据项目需要扩展更多断言方法(比如NotNull、IsInstanceOfType之类的)。
2. 自定义TraceListener让Trace.Assert抛异常
如果你不想自己写工具类,想复用Trace.Assert的语法,可以全局替换Trace的监听器,让它在断言失败时抛出异常:
public class ExceptionThrowingTraceListener : TraceListener { public override void Write(string message) { } public override void WriteLine(string message) { } public override void Fail(string message) { throw new InvalidOperationException($"断言失败:{message}"); } public override void Fail(string message, string detailMessage) { throw new InvalidOperationException($"断言失败:{message},详情:{detailMessage}"); } }
然后在程序启动的地方(比如Program.cs)添加这个监听器:
// 先清空默认的监听器,避免同时弹出对话框或者输出日志 Trace.Listeners.Clear(); Trace.Listeners.Add(new ExceptionThrowingTraceListener());
这样所有的Trace.Assert失败时都会抛出异常了,不过这个是全局生效的,适合整个项目都需要这个行为的场景。
3. 直接写条件判断抛异常(最直观,适合业务强制校验)
如果你的场景是不管Debug还是Release都必须校验的业务逻辑,直接写条件判断反而更清晰,不用绕弯子:
public int Save(Guid? personGuid, Person person) { if (person.Id > 0) { Update(person); } if (!personGuid.HasValue) { throw new InvalidOperationException("保存新资源时必须提供有效的GUID"); } SaveToDb(personGuid, person); }
这种方式没有额外的依赖,别人看代码一眼就能明白这里的校验逻辑,适合那些不能跳过的关键业务检查。
内容的提问来源于stack exchange,提问作者mft25

