C#中using语句下Y释放时PropertyX状态及实现方案问询
关于Disposable资源释放与对象引用的问题
首先看这段代码:
class A { TypeX PropertyX; void SomeMethod() { using (DisposableType y = new DisposableType()) { PropertyX = y.GetX(); } } }
对应的问题:
当DisposableType实例Y被释放时,PropertyX会处于什么状态?
若不清楚Y释放时会连带处理哪些资源,是否应当采用如下实现方式?
给出的备选实现:
class A : IDisposable { TypeX PropertyX { get; set;} DisposableType Y { get; set; } void SomeMethod() { using (Y = new DisposableType()) { PropertyX = Y.GetX(); } } void Dispose() { Y.Dispose(); } }
第一个问题:Y被释放时PropertyX的状态
这得看DisposableType.GetX()返回的是什么:
- 如果是值类型(比如int、自定义struct):PropertyX存的是值的副本,Y释放后完全不影响,PropertyX该咋用咋用。
- 如果是引用类型:就得分情况
- 要是返回的引用指向Y内部持有的资源,而且Y.Dispose()会把这个资源销毁/释放,那PropertyX就成了“悬空引用”,之后再访问大概率会抛出
ObjectDisposedException或者其他异常。 - 要是返回的引用指向的是和Y无关的独立对象(比如Y只是帮忙创建了这个对象,但不负责它的生命周期),那Y释放后PropertyX照样能用,没毛病。
- 要是返回的引用指向Y内部持有的资源,而且Y.Dispose()会把这个资源销毁/释放,那PropertyX就成了“悬空引用”,之后再访问大概率会抛出
第二个问题:备选实现是否可行?
这种写法不仅解决不了问题,还会添乱:
- 重复释放风险:using块会自动调用Y.Dispose(),你在A.Dispose()里又调用一次。虽然规范要求Disposable类型要支持重复Dispose不报错,但总有不遵守规范的实现,这么搞很容易触发异常。
- 生命周期混乱:每次调用SomeMethod()都会给Y赋值新实例,旧实例直接丢给GC回收;而且using块已经把当前Y释放了,A.Dispose()里再调用Dispose()纯纯多余。
- 没解决核心问题:要是PropertyX指向的是Y内部的资源,就算把Y和A绑定,只要Y被释放,PropertyX的引用还是会失效——除非你不让Y被释放,那using块从一开始就不该用。
正确的处理思路
要是不确定DisposableType释放时会影响啥,按这个顺序来:
- 先查DisposableType和GetX()的文档,搞清楚返回值的生命周期到底归谁管。
- 如果GetX()返回的资源必须和Y同生共死,那要么别在using块里保存这个引用,要么去掉using块,让A持有Y的实例,在A.Dispose()里统一释放Y(这时候A实现IDisposable是合理的)。
- 如果GetX()返回的是独立资源,那原代码完全没问题,不用改。
内容的提问来源于stack exchange,提问作者Piglet
相关产品推荐
相关产品推荐

