CSharp的接口显式实现和IDisposable接口与using关键字的关系

近日,有同事写的http下载模块出现了一些问题,在Review代码的过程中发现一个奇怪的地方:

针对从WebResponse中取出来的Stream,在用完以后,对于Stream手动依次调用了Close、Dispose。

if (reader != null)
{
    reader.Close();
    reader.Dispose();
}

而紧接着,对于WebResponse的操作却仅仅调用了Close。

if (response != null)
{
    response.Close();
}

而实际上,针对WebResponse的使用范例,无一例外都是使用了using关键字来处理Dispose的。

using (WebResponse response = request.GetResponse())
{
    ...
    response.Close();
}

这表明,WebResponse在使用完后,需要进行Dispose,于是我尝试给他加上Dispose调用,却发现通过response的引用,无法点出Dispose来,询问原作者后,也表示因为点不出来,所以认为没这个接口,就没有调用了。但是,查看WebResponse的定义,发现它是有继承IDisposable的。

namespace System.Net
{
    public abstract class WebResponse : MarshalByRefObject, IDisposable, ISerializable
    {
        ...
    }
}

那么,为什么会点不出Dispose方法来呢?

原来,WebResponse对IDisposable接口的实现采用了显式实现。

void IDisposable.Dispose()
{
    ...
}

对于显式实现的接口,无法在子类的引用中调用该实现,而必须使用基类的引用。

if (response != null)
{
    response.Close();
    (response as IDisposable).Dispose();
}

这样,可以成功调用Dispose,对其进行释放。

那么,为什么使用using关键字时可以成功释放呢?那是因为using在CSharp中的潜规则是,将赋予它的引用,强转为IDisposable,然后调用它的Dispose接口。

using (object)
{
    ...
}
上述代码相当于
...
(object as IDisposable).Dispose();

特别的,如果传入的object并没有继承自IDisposable,编译时会直接报错。

对于踩了这样一个坑,说明这位同事的基础知识掌握还不够,并且在技术选型时有些盲目自信,在没有完全掌握基础细节的情况下,擅自改变了范例代码的常见用法,导致了这个结果。

在此,呼吁各位基础还不扎实的同学,在学习范例代码的时候要么彻底搞明白这么写的原因,要么就严格模仿,不要擅自去修改,以免采坑,好自为之。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值