C#编译器会自动处理IDisposable对象吗?
假设我有一个方法C#编译器会自动处理IDisposable对象吗?,c#,.net,idisposable,compiler-optimization,C#,.net,Idisposable,Compiler Optimization,假设我有一个方法publicstaticrectangledrawrectangle(向量原点,向量大小),它返回类型为Rectangle:IDisposable 如果我只调用方法DrawRectangle(origin,size),但不将返回值赋给变量myRectangle=DrawRectangle(origin,size),编译器会自动检测到这一点并调用DrawRectangle(origin,size).Dispose(),还是我必须自己做?否.点 最终,终结器会执行,但不会。它不会自动
publicstaticrectangledrawrectangle(向量原点,向量大小)
,它返回类型为Rectangle:IDisposable
如果我只调用方法DrawRectangle(origin,size)
,但不将返回值赋给变量myRectangle=DrawRectangle(origin,size)
,编译器会自动检测到这一点并调用DrawRectangle(origin,size).Dispose()
,还是我必须自己做?否.点
最终,终结器会执行,但不会。它不会自动调用Dispose。如果您的
矩形类实现了IDisposable
,请在可行时尝试使用(){…}
语句
如果希望CLR调用Dispose方法,通常建议在类中实现所谓的。但是,我不会依赖CLR,也不会等待GC收集对象并使用子句。编译器将代码构建到程序集中,并且不负责任何执行。net运行时是运行代码的,更具体地说,垃圾收集器处理内存清理。通常,最好的做法是在using块内部调用实现IDisposable的对象。例如:
使用(var obj=新对象)
{
做你的事
}
这将有助于运行时理解对象何时超出范围并提前清理,但只要您不保留对对象的引用,运行时最终将清理对象并为您处置它。我只能想到两种情况,编译器会自动调用dispose;最明显的是:
using(var obj = ... )
{
// some code
}
这是一条明确的指令,表示“最后,无论成功还是失败,如果obj
为非空,请调用obj.Dispose()
”。基本上,它扩展到:
{
var obj = ...
try {
// some code
} finally {
if(obj != null) obj.Dispose();
}
}
另一个是foreach
,迭代器在其中进行处理-尽管它变得有点复杂,因为IEnumerator
没有指定需要IDisposable
(相反,IEnumerator
确实指定了这一点),从技术上讲,IEnumerable
甚至不需要foreach
,但基本上:
foreach(var item in sequence) {
// some code
}
可以表示为(尽管规范可能会略有不同):
在所有其他情况下,处理资源是您的责任
如果不确保调用了Dispose()
,那么在GC最终收集对象之前不会发生任何事情如果存在终结器(不一定存在,而且通常不存在),将调用终结器-但这与Dispose()
不同。它可能会(取决于每种类型的实现)最终执行与Dispose()
相同的操作:但它可能不会。我还要提到,编译器从不处理正在编译的代码,只有CLR。终结器可以调用Dispose
,但它当然不必这样做。处置和终结/垃圾收集是分开的。@ErikPhilips meh;我不确定这是一个有用的区别。当然,在某些地方,编译器会添加一个Dispose
foreach
和使用
是我的head@TomTomGC只是清理内存,如果有内存,则调用finalize;它从来没有做过任何与IDisposable
/Dispose()
-虽然终结器实现可能(如果它选择)在某些方面,但我认为终结器的可用性可能弊大于利,因为它们通常都没有正确编写以“大部分工作”的代码。终结器应该重要的唯一时间是在执行诸如插入实现IDisposable
的不可变对象(例如,保存预渲染图片的位图)之类的操作时,在这种情况下,它们可以与WeakReference
合理组合。在一些情况下,正确的清理非常困难(例如,基类对象创建一个IDisposable
,然后派生类构造函数抛出一个异常),但是…“否”和“使用using
”。标记为重复:@igrimpe不确定它是重复的;这个问题特别询问编译器如果集合返回的枚举器的类类型没有实现IDisposable
(与类型IEnumerator
)相反,我相信C#会假设枚举器实例没有实现IDisposable
,并且不会尝试强制转换,尽管实际返回的实例可能是实现IDisposable
@supercat yes的派生类型,但我注意到:请参见“技术上”。等价物示例旨在说明和语义等价,而不是精确的实现。作为doe,它是否尝试对子类型场景进行强制转换:我必须查看reflector以进行评论。在我自己的IL生成器中,我只禁用了密封的/struct,因此不能有子类。如果GetEnumerator
返回的类型实现了IDisposable
,那么编译器将对其调用Dispose
。遗憾的是,据我所知,编译器将查找的唯一名称是GetEnumerator
,因为如果它查找例如GetForEachEnumerator
,则可能返回一个未实现任何接口的结构(因此不必实现IDisposable
),虽然GetEnumerator
可以返回一个实现了IEnumerator
的类,因此必须实现IDisposable
@supercat,但您可以使用显式+公共实现来实现,IIRCOne可以做到这一点,如果您愿意要求希望使用IEnumerator
的用户首先强制转换为IEnumerable
,或者调用名为oth的方法
{
var iter = sequence.GetEnumerator();
using(iter as IDisposable)
{
while(iter.MoveNext())
{ // note that before C# 5, "item" is declared *outside* the while
var item = iter.Current;
// some code
}
}
}