C#中仅能在函数中抛出异常?自定义异常抛出问题咨询
问题解析与异常处理机制说明
首先明确:C#完全支持在属性的get/set访问器中抛出异常,你遇到的问题不是语法限制,而是属性set访问器的逻辑写反了,导致异常触发条件根本没满足。
1. 为什么set访问器里的异常没触发?
看你的set访问器代码:
public double HoursParked { get => _hoursParked; set if (_hoursParked > 24) // 这里判断的是旧的字段值,不是要设置的新值! { throw new ParkingException(); } else { _hoursParked = Math.Ceiling(value); } }
这段代码的逻辑是:只有当原来的停车时长已经超过24小时时,设置新值才会抛异常。如果原来的_hoursParked≤24,哪怕你传入一个value=30,代码也会直接把_hoursParked改成Math.Ceiling(30)=30,完全不会触发异常判断——这就是你调试时看不到异常的原因。
正确的逻辑应该是先检查要设置的新值value是否非法,再决定是否赋值:
public double HoursParked { get => _hoursParked; set { if (value > 24) // 检查传入的新值 { throw new ParkingException(); } _hoursParked = Math.Ceiling(value); } }
这样只要你试图设置一个超过24小时的值,set访问器就会立刻抛出异常,拦截非法值存入字段。
2. 为什么移到DisplayTotalCost里能触发异常?
你的DisplayTotalCost方法里判断的是当前已经存入的HoursParked值:
public void DisplayTotalCost() { if(HoursParked > 24) { throw new ParkingException(); } }
因为之前set访问器的逻辑错误,允许了超过24的值存入_hoursParked,所以当你调用这个方法时,读取到的当前值已经大于24,自然触发了异常。但这属于事后检查,而属性访问器的设计初衷之一就是事前拦截非法输入,避免非法值被存储。
3. C#异常处理的核心要点
- 属性的get/set本质上是编译器自动生成的
get_HoursParked()和set_HoursParked(double value)方法,和普通方法完全一样,支持抛出异常。.NET类库中也有大量例子,比如索引器List<T>[index]在索引越界时会抛出ArgumentOutOfRangeException。 - 异常的作用是报告程序运行时的非法状态或错误,不管是在方法、属性访问器还是构造函数里,只要遇到非法情况都可以抛出。
- 自定义异常建议直接继承
Exception,而非ApplicationException——微软后续文档明确说明,ApplicationException的设计初衷并未达成,自定义异常应直接继承基类Exception。
内容的提问来源于stack exchange,提问作者user21279196
相关产品推荐
相关产品推荐

