Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#一次性问题_C#_Garbage Collection_Idisposable_Disposable - Fatal编程技术网

C#一次性问题

C#一次性问题,c#,garbage-collection,idisposable,disposable,C#,Garbage Collection,Idisposable,Disposable,例如,如果我忘记使用语句编写,垃圾收集器是否会自动释放与某个IDisposable实例相关联的非托管资源(不管实际是什么) 显然,我不知道什么时候会发生这种情况,但是如果我不关心这些资源,并且我很确定它们最终会被处置,那么将IDisposable留给GC是否可以?是的,它们最终会被清理。当您需要确定性资源清理时,如GDI、Sql和其他基于系统句柄的代码,或潜在的内存大的对象(如DataTable),您只需要使用(呵呵…) 编辑:这是假设您实现了正确的Dispose模式,并且拥有析构函数调用Dis

例如,如果我忘记使用语句编写
,垃圾收集器是否会自动释放与某个
IDisposable
实例相关联的非托管资源(不管实际是什么)


显然,我不知道什么时候会发生这种情况,但是如果我不关心这些资源,并且我很确定它们最终会被处置,那么将
IDisposable
留给
GC
是否可以?

是的,它们最终会被清理。当您需要确定性资源清理时,如GDI、Sql和其他基于系统句柄的代码,或潜在的内存大的对象(如
DataTable
),您只需要使用
(呵呵…)


编辑:这是假设您实现了正确的
Dispose
模式,并且拥有析构函数调用
Dispose

如果对象通过在终结器中包含对Dispose方法的条件调用正确实现IDisposable接口,那么GC将在收集过程中触发对该对象的处置(通过终结器)

有些事情会导致这种情况不会发生,但如果遵循标准模式,那么在大多数情况下它都会起作用


如果对象在终结器中不包含处置代码,则所有赌注都将被取消。在太阳超新星出现之前,非托管资源可能不会被处置。

不一定。这取决于您如何获得非托管资源

如果您拥有非托管资源的直接句柄(可能是
IntPtr
),那么您应该拥有终结器或使用
SafeHandle
…否则您肯定会泄漏非托管资源

如果您的类型只是引用了类似于
FileStream
的内容,那么您应该期望该类型将有一个终结器

现在,很少需要从类型中直接访问非托管资源,如果您使用的是框架类型,它们确实应该进行适当的清理(但不确定性地清理)。不过,这是可能的

例如,如果我忘记编写using语句,垃圾收集器会自动释放与某个IDisposable实例关联的非托管资源(不管是什么)吗

通常,但不一定。一次性资源的作者需要做正确的事情

显然,我不知道什么时候会发生这种情况,但是如果我不关心这些资源,并且我认为它们最终会被处置,那么将IDisposable留给GC可以吗

您的问题假定是错误的。垃圾收集器从不调用Dispose,永远。相反,垃圾收集器调用析构函数(或者如果您愿意,调用“终结器”)。对于健忘的用户,析构函数可能调用Dispose,也可能不调用Dispose

您的问题还表明您的态度不好。您可能不关心资源是否被延迟释放,但另一个程序肯定会关心!如果您的客户运行的两个程序都试图访问同一个非托管资源,一个由您编写,另一个由其他人编写,该怎么办?做一个好公民;释放您稀缺的资源一旦你使用完它们,其他程序就可以使用它们。这就是“使用”的真正目的——礼貌地确保稀缺资源得到快速回收

Dispose模式的正确实现将确保如果用户忘记调用Dispose,析构函数将清除非托管资源,并且如果资源记住,将确保析构函数不会清除资源

如果您是为拥有非托管资源的类编写Dispose实现的人员,则您有责任在用户未正确调用Dispose的情况下正确编写析构函数代码。编写此代码的正确方法有非常详细的文档;请遵循此模式。请参阅Jon对r一些有用的链接


还要注意,如果您正在编写这样一个类,那么您还需要让它在用户无法调用Dispose的情况下工作。例如,假设构造函数分配两个非托管资源,在分配第一个和第二个资源之间,会在构造函数外部引发并捕获异常。T因此,用户无法调用Dispose,因为新对象引用的分配发生在构造函数成功运行之后,而构造函数从未成功完成运行。如何释放第一个非托管资源?只有析构函数才能释放它。析构函数必须在这种情况下保持健壮;被破坏的对象可能从未完全构造过,因此您不能依赖构造函数的任何不变量。

系统库中的任何
IDisposable
将在最终确定后自行处理(或者至少将采取与处理相同的大多数步骤)


对于第三方的东西没有任何保证——例如,如果您使用的是某个C库的接口,该接口为您提供句柄,那么在卸载库之前,这些句柄可能不会被清除(这通常只发生在应用程序退出时)。但是,很常见的情况是忘记使用
Dispose
using
(或甚至不知道或不关心某种类型是一次性的),我认为任何没有考虑到它的.net库都写得很糟糕。

当创建对象时,如果它覆盖object.Finalize,系统会将其添加到具有注册终结器的对象列表中。该列表中的对象以及它们直接或间接引用的对象将不符合删除条件,除非或直到对它们调用C.SuppressFinalize,或者从列表中删除它们。如果系统注意到这样一个对象如果不存在于可终结对象列表中,则可以删除它