如何在.net 中处理一个类?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12368/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to dispose a class in .net?
提问by Jorrit Reedijk
The .NET garbage collector will eventually free up memory, but what if you want that memory back immediately? What code do you need to use in a class MyClassto call
.NET 垃圾收集器最终会释放内存,但如果您想要立即收回内存怎么办?需要在类中使用什么代码MyClass来调用
MyClass.Dispose()
and free up all the used space by variables and objects in MyClass?
并释放变量和对象中的所有已用空间MyClass?
回答by Curt Hagenlocher
IDisposable has nothing to do with freeing memory. IDisposable is a pattern for freeing unmanagedresources -- and memory is quite definitely a managed resource.
IDisposable 与释放内存无关。IDisposable 是一种释放非托管资源的模式——而内存绝对是一种托管资源。
The links pointing to GC.Collect() are the correct answer, though use of this function is generally discouraged by the Microsoft .NET documentation.
指向 GC.Collect() 的链接是正确答案,尽管 Microsoft .NET 文档通常不鼓励使用此函数。
Edit:Having earned a substantial amount of karma for this answer, I feel a certain responsibility to elaborate on it, lest a newcomer to .NET resource management get the wrong impression.
编辑:为这个答案赚了大量的业力,我觉得有责任详细说明它,以免 .NET 资源管理的新手得到错误的印象。
Inside a .NET process, there are two kinds of resource -- managed and unmanaged. "Managed" means that the runtime is in control of the resource, while "unmanaged" means that it's the programmer's responsibility. And there really is only one kind of managed resource that we care about in .NET today -- memory. The programmer tells the runtime to allocate memory and after that it's up to the runtime to figure out when the memory can freed. The mechanism that .NET uses for this purpose is called garbage collectionand you can find plenty of information about GC on the internet simply by using Google.
在 .NET 进程中,有两种资源——托管和非托管。“托管”意味着运行时控制资源,而“非托管”意味着它是程序员的责任。而今天在 .NET 中,我们真正关心的只有一种托管资源——内存。程序员告诉运行时分配内存,然后由运行时确定何时可以释放内存。.NET 用于此目的的机制称为垃圾收集,您只需使用 Google 即可在互联网上找到大量有关 GC 的信息。
For the other kinds of resources, .NET doesn't know anything about cleaning them up so it has to rely on the programmer to do the right thing. To this end, the platform gives the programmer three tools:
对于其他类型的资源,.NET 对清理它们一无所知,因此它必须依靠程序员来做正确的事情。为此,平台为程序员提供了三种工具:
- The IDisposable interface and the "using" statement in VB and C#
- Finalizers
- The IDisposable pattern as implemented by many BCL classes
- VB 和 C# 中的 IDisposable 接口和“使用”语句
- 终结者
- 由许多 BCL 类实现的 IDisposable 模式
The first of these allows the programmer to efficiently acquire a resource, use it and then release it all within the same method.
第一个允许程序员有效地获取资源,使用它,然后在同一方法中释放它。
using (DisposableObject tmp = DisposableObject.AcquireResource()) {
// Do something with tmp
}
// At this point, tmp.Dispose() will automatically have been called
// BUT, tmp may still a perfectly valid object that still takes up memory
If "AcquireResource" is a factory method that (for instance) opens a file and "Dispose" automatically closes the file, then this code cannot leak a file resource. But the memory for the "tmp" object itself may well still be allocated. That's because the IDisposable interface has absolutely no connection to the garbage collector. If you didwant to ensure that the memory was freed, your only option would be to call GC.Collect()to force a garbage collection.
如果“AcquireResource”是(例如)打开文件并且“Dispose”自动关闭文件的工厂方法,则此代码不会泄漏文件资源。但是“tmp”对象本身的内存很可能仍然被分配。那是因为 IDisposable 接口完全没有与垃圾收集器的连接。如果您确实想确保释放内存,您唯一的选择是调用GC.Collect()强制垃圾回收。
However, it cannot be stressed enough that this is probably not a good idea. It's generally much better to let the garbage collector do what it was designed to do, which is to manage memory.
然而,无论如何强调这可能不是一个好主意。通常让垃圾收集器执行它设计的任务要好得多,即管理内存。
What happens if the resource is being used for a longer period of time, such that its lifespan crosses several methods? Clearly, the "using" statement is no longer applicable, so the programmer would have to manually call "Dispose" when he or she is done with the resource. And what happens if the programmer forgets? If there's no fallback, then the process or computer may eventually run out of whichever resource isn't being properly freed.
如果资源使用时间较长,以至于其生命周期跨越多种方法,会发生什么情况?显然,“using”语句不再适用,因此程序员在使用完资源后必须手动调用“Dispose”。如果程序员忘记了会发生什么?如果没有回退,那么进程或计算机最终可能会耗尽未正确释放的资源。
That's where finalizers come in. A finalizer is a method on your class that has a special relationship with the garbage collector. The GC promises that -- before freeing the memory for any object of that type -- it will first give the finalizer a chance to do some kind of cleanup.
这就是终结器的用武之地。终结器是类中的一种方法,它与垃圾收集器有着特殊的关系。GC 承诺——在为该类型的任何对象释放内存之前——它将首先让终结器有机会进行某种清理。
So in the case of a file, we theoretically don't need to close the file manually at all. We can just wait until the garbage collector gets to it and then let the finalizer do the work. Unfortunately, this doesn't work well in practice because the garbage collector runs non-deterministically. The file may stay open considerably longer than the programmer expects. And if enough files are kept open, the system may fail when trying to open an additional file.
所以在文件的情况下,理论上我们根本不需要手动关闭文件。我们可以等到垃圾收集器找到它,然后让终结器完成工作。不幸的是,这在实践中效果不佳,因为垃圾收集器非确定性地运行。文件保持打开状态的时间可能比程序员预期的要长得多。如果保持打开的文件足够多,系统在尝试打开其他文件时可能会失败。
For most resources, we want both of these things. We want a convention to be able to say "we're done with this resource now" and we want to make sure that there's at least some chance for the cleanup to happen automatically if we forget to do it manually. That's where the "IDisposable" pattern comes into play. This is a convention that allows IDispose and a finalizer to play nicely together. You can see how the pattern works by looking at the official documentation for IDisposable.
对于大多数资源,我们需要这两样东西。我们想要一个约定能够说“我们现在已经完成了这个资源”,并且我们想要确保如果我们忘记手动进行清理,至少有一些机会自动进行清理。这就是“IDisposable”模式发挥作用的地方。这是一个约定,允许 IDispose 和终结器很好地协同工作。您可以通过查看IDisposable的官方文档来了解该模式的工作原理。
Bottom line:If what you really want to do is to just make sure that memory is freed, then IDisposable and finalizers will not help you. But the IDisposable interface is part of an extremely important pattern that all .NET programmers should understand.
底线:如果您真正想做的只是确保释放内存,那么 IDisposable 和终结器将无济于事。但是 IDisposable 接口是所有 .NET 程序员都应该理解的极其重要的模式的一部分。
回答by Patrik Svensson
You can only dispose instances that implement the IDisposable interface.
您只能处置实现 IDisposable 接口的实例。
To force a garbage collect to free up the (unmanaged) memory immediately:
强制垃圾收集立即释放(非托管)内存:
GC.Collect();
GC.WaitForPendingFinalizers();
This is normally bad practice, but there is for example a bug in the x64-version of the .NET framework that makes the GC behave strange in some scenarios, and then you might want to do this. I don't know if the bug have been resolved yet. Does anyone know?
这通常是不好的做法,但例如在 .NET 框架的 x64 版本中存在一个错误,该错误使 GC 在某些情况下表现得很奇怪,然后您可能想要这样做。不知道bug有没有解决。有人知道吗?
To dispose a class you do this:
要处理一个类,你可以这样做:
instance.Dispose();
or like this:
或者像这样:
using(MyClass instance = new MyClass())
{
// Your cool code.
}
that will translate at compile-time to:
这将在编译时转换为:
MyClass instance = null;
try
{
instance = new MyClass();
// Your cool code.
}
finally
{
if(instance != null)
instance.Dispose();
}
You can implement the IDisposable interface like this:
您可以像这样实现 IDisposable 接口:
public class MyClass : IDisposable
{
private bool disposed;
/// <summary>
/// Construction
/// </summary>
public MyClass()
{
}
/// <summary>
/// Destructor
/// </summary>
~MyClass()
{
this.Dispose(false);
}
/// <summary>
/// The dispose method that implements IDisposable.
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// The virtual dispose method that allows
/// classes inherithed from this one to dispose their resources.
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Dispose managed resources here.
}
// Dispose unmanaged resources here.
}
disposed = true;
}
}
回答by Keith
The responses to this question have got more than a little confused.
对这个问题的回答有点令人困惑。
The title asks about disposal, but then says that they want memory back immediately.
标题询问处置,然后说他们想要立即恢复记忆。
.Net is managed, which means that when you write .Net apps you don't need to worry about memory directly, the cost is that you don't have direct control over memory either.
.Net 是托管的,这意味着当您编写 .Net 应用程序时,您无需直接担心内存,代价是您也无法直接控制内存。
.Net decides when it's best to clean up and free memory, not you as the .Net coder.
.Net 决定何时最好清理和释放内存,而不是您作为 .Net 编码员。
The Disposeis a way to tell .Net that you're done with something, but it won't actually free up the memory until it's the best time to do so.
这Dispose是一种告诉 .Net 你已经完成某事的方法,但它实际上不会释放内存,直到它是最好的时间。
Basically .Net will actually collect the memory back when it's easiest for it to do so - it's very good at deciding when. Unless you're writing something very memory intensive you normally don't need to overrule it (this is part of the reason games aren't often written in .Net yet - they need complete control)
基本上,.Net 会在最简单的时候回收内存——它非常擅长决定何时回收。除非你正在写一些非常占用内存的东西,否则你通常不需要否决它(这是游戏不经常用 .Net 编写的部分原因 - 他们需要完全控制)
In .Net you can use GC.Collect()to force it to immediately, but that is almost always bad practise. If .Net hasn't cleaned it up yet that means it isn't a particularly good time for it to do so.
在 .Net 中,您可以使用GC.Collect()它立即强制它,但这几乎总是不好的做法。如果 .Net 还没有清理它,这意味着它不是一个特别好的时间这样做。
GC.Collect()picks up the objects that .Net identifies as done with. If you haven't disposed an object that needs it .Net may decide to keep that object. This means that GC.Collect()is only effective if you correctly implement your disposable instances.
GC.Collect()拾取 .Net 识别为已完成的对象。如果您尚未处理需要它的对象,.Net 可能会决定保留该对象。这意味着GC.Collect()只有在您正确实施一次性实例时才有效。
GC.Collect()is nota replacement for correctly using IDisposable.
GC.Collect()是不是对正确使用IDisposable的一个替代品。
So Dispose and memory are not directly related, but they don't need to be. Correctly disposing will make your .Net apps more efficient and therefore use less memory though.
所以 Dispose 和 memory 没有直接关系,但它们不需要。正确处理将使您的 .Net 应用程序更高效,因此使用更少的内存。
99% of the time in .Net the following is best practice:
在 .Net 中 99% 的时间以下是最佳实践:
Rule 1:If you don't deal with anything unmanagedor that implements IDisposablethen don't worry about Dispose.
规则 1:如果你不处理任何非托管或实现的东西,IDisposable那么不要担心 Dispose。
Rule 2:If you have a local variable that implements IDisposable make sure that you get rid of it in the current scope:
规则 2:如果您有一个实现 IDisposable 的局部变量,请确保在当前范围内删除它:
//using is best practice
using( SqlConnection con = new SqlConnection("my con str" ) )
{
//do stuff
}
//this is what 'using' actually compiles to:
SqlConnection con = new SqlConnection("my con str" ) ;
try
{
//do stuff
}
finally
{
con.Dispose();
}
Rule 3:If a class has a property or member variable that implements IDisposable then that class should implement IDisposable too. In that class's Dispose method you can also dispose of your IDisposable properties:
规则 3:如果一个类有一个实现 IDisposable 的属性或成员变量,那么该类也应该实现 IDisposable。在该类的 Dispose 方法中,您还可以处理 IDisposable 属性:
//rather basic example
public sealed MyClass :
IDisposable
{
//this connection is disposable
public SqlConnection MyConnection { get; set; }
//make sure this gets rid of it too
public Dispose()
{
//if we still have a connection dispose it
if( MyConnection != null )
MyConnection.Dispose();
//note that the connection might have already been disposed
//always write disposals so that they can be called again
}
}
This isn't really complete, which is why the example is sealed. Inheriting classes may need to observe the next rule...
这并不是真正完整的,这就是该示例被密封的原因。继承类可能需要遵守下一条规则......
Rule 4:If a class uses an unmanagedresource then implement IDispose andadd a finaliser.
规则 4:如果类使用非托管资源,则实现 IDispose并添加终结器。
.Net can't do anything with the unmanagedresource, so now we are talking about memory. If you don't clean it up you can get a memory leak.
.Net 不能对非托管资源做任何事情,所以现在我们谈论的是内存。如果你不清理它,你可能会出现内存泄漏。
The Dispose method needs to deal with both managedand unmanagedresources.
Dispose 方法需要处理托管和非托管资源。
The finaliser is a safety catch - it ensures that if someone else creates and instance of your class and fails to dispose it the 'dangerous' unmanagedresources can still be cleaned up by .Net.
终结器是一个安全陷阱 - 它确保如果其他人创建了您的类的实例并且未能处理它,“危险的”非托管资源仍然可以被 .Net 清理。
~MyClass()
{
//calls a protected method
//the false tells this method
//not to bother with managed
//resources
this.Dispose(false);
}
public void Dispose()
{
//calls the same method
//passed true to tell it to
//clean up managed and unmanaged
this.Dispose(true);
//as dispose has been correctly
//called we don't need the
//'backup' finaliser
GC.SuppressFinalize(this);
}
Finally this overload of Dispose that takes a boolean flag:
最后这个带有布尔标志的 Dispose 重载:
protected virtual void Dispose(bool disposing)
{
//check this hasn't been called already
//remember that Dispose can be called again
if (!disposed)
{
//this is passed true in the regular Dispose
if (disposing)
{
// Dispose managed resources here.
}
//both regular Dispose and the finaliser
//will hit this code
// Dispose unmanaged resources here.
}
disposed = true;
}
Note that once this is all in place other managed code creating an instance of your class can just treat it like any other IDisposable (Rules 2 and 3).
请注意,一旦这一切就绪,其他创建类实例的托管代码就可以像对待任何其他 IDisposable 一样对待它(规则 2 和 3)。
回答by Brian Lyttle
Would it be appropriate to also mention that dispose doesn't always refer to memory? I dispose resources such a references to files more often than memory. GC.Collect() directly relates to the CLR garbage collector and may or may not free memory (in Task Manager). It will likely impact your application in negative ways (eg performance).
还提到 dispose 并不总是指内存是否合适?我比内存更频繁地处理资源,例如对文件的引用。GC.Collect() 与 CLR 垃圾收集器直接相关,可能会释放内存,也可能不会释放内存(在任务管理器中)。它可能会以负面方式(例如性能)影响您的应用程序。
At the end of the day why do you want the memory back immediately? If there is memory pressure from elsewhere the OS will get you memory in most cases.
归根结底,你为什么要立即恢复记忆?如果存在来自其他地方的内存压力,在大多数情况下,操作系统会为您提供内存。
回答by Scott Dorman
Take a look at this article
看看这篇文章
Implementing the Dispose pattern, IDisposable, and/or a finalizer has absolutely nothing to do with when memory gets reclaimed; instead, it has everything to do with telling the GC howto reclaim that memory. When you call Dispose() you are in no way interacting with the GC.
实现 Dispose 模式、IDisposable 和/或终结器与回收内存完全无关;相反,它与告诉 GC如何回收该内存有关。当您调用 Dispose() 时,您绝不会与 GC 进行交互。
The GC will only run when it determines the need to (called memory pressure) and then (and only then) will it deallocate memory for unused objects and compact the memory space.
GC 仅在确定需要(称为内存压力)时才会运行,然后(并且仅在那时)才会为未使用的对象释放内存并压缩内存空间。
You couldcall GC.Collect() but you really shouldn't unless there is a verygood reason to (which is almost always "Never"). When you force an out-of-band collection cycle like this you actually cause the GC to do more work and ultimately can end up hurting your applications performance. For the duration of the GC collection cycle your application is actually in a frozen state...the more GC cycles that run, the more time your application spends frozen.
你可以调用GC.Collect(),但你真的不应该,除非有非常充分的理由(这几乎总是“从不”)。当您强制执行这样的带外收集周期时,您实际上会导致 GC 做更多的工作,最终可能会损害您的应用程序性能。在 GC 收集周期的持续时间内,您的应用程序实际上处于冻结状态……运行的 GC 周期越多,您的应用程序花费的时间就越长。
There are also some native Win32 API calls you can make to free your working set, but even those should be avoided unless there is a verygood reason to do it.
也有一些本地的Win32 API调用,你可以对你的自由工作集,但即使是那些应该避免,除非有非常充分的理由这样做。
The whole premise behind a gargbage collected runtime is that you don't need to worry (as much) about when the runtime allocates/deallocates actual memory; you only need to worry about making sure the your object knows how to clean up after itself when asked.
垃圾收集运行时背后的整个前提是您不需要(尽可能多地)担心运行时何时分配/释放实际内存;您只需要担心确保您的对象知道如何在被询问时自行清理。
回答by Darren Kopp
public class MyClass : IDisposable
{
public void Dispose()
{
// cleanup here
}
}
then you can do something like this
那么你可以做这样的事情
MyClass todispose = new MyClass();
todispose.Dispose(); // instance is disposed right here
or
或者
using (MyClass instance = new MyClass())
{
}
// instance will be disposed right here as it goes out of scope
回答by jfs
Complete explanation by Joe Duffy on "Dispose, Finalization, and Resource Management":
Joe Duffy 对“处置、终结和资源管理”的完整解释:
Earlier in the .NET Framework's lifetime, finalizers were consistently referred to as destructors by C# programmers. As we become smarter over time, we are trying to come to terms with the fact that the Dispose method is really more equivalent to a C++ destructor (deterministic), while the finalizer is something entirely separate (nondeterministic). The fact that C# borrowed the C++ destructor syntax (i.e. ~T()) surely had at least a little to do with the development of this misnomer.
在 .NET Framework 生命周期的早期,终结器一直被 C# 程序员称为析构函数。随着时间的推移,我们变得越来越聪明,我们试图接受这样一个事实,即Dispose 方法实际上更等同于 C++ 析构函数(确定性),而 终结器是完全独立的(非确定性)。C# 借用了 C++ 析构函数语法(即 ~T())这一事实肯定至少与这种用词不当的发展有关。
回答by Ashley Frieze
I wrote a summary of Destructors and Dispose and Garbage collection on http://codingcraftsman.wordpress.com/2012/04/25/to-dispose-or-not-to-dispose/
我在http://codingcraftsman.wordpress.com/2012/04/25/to-dispose-or-not-to-dispose/上写了析构函数和处置和垃圾收集的摘要
To answer the original question:
要回答原始问题:
- Don't try to manage your memory
- Dispose is not about memory management, it's about unmanaged resource management
- Finalizers are an innate part of the Dispose pattern and actually slow down memory freeing of managed objects (as they have to go into the Finalization queue unless already Dispose d)
- GC.Collect is bad as it makes some short-lived objects appear to be required for longer and so slows them down from being collected.
- 不要试图管理你的记忆
- Dispose 不是关于内存管理,而是关于非托管资源管理
- Finalizers 是 Dispose 模式的固有部分,实际上减慢了托管对象的内存释放(因为它们必须进入 Finalization 队列,除非已经 Dispose d)
- GC.Collect 很糟糕,因为它使一些生命周期短的对象看起来需要更长的时间,因此减慢了它们被收集的速度。
However, GC.Collect could be useful if you had a performance critical section of code and wanted to reduce the likelihood of Garbage Collection slowing it down. You call that before.
但是,如果您有代码的性能关键部分并希望减少垃圾收集减慢它的可能性,则 GC.Collect 可能会很有用。你以前这么叫。
On top of that, there is an argument in favour of this pattern:
最重要的是,有一个支持这种模式的论据:
var myBigObject = new MyBigObject(1);
// something happens
myBigObject = new MyBigObject(2);
// at the above line, there are temporarily two big objects in memory and neither can be collected
vs
对比
myBigObject = null; // so it could now be collected
myBigObject = new MyBigObject(2);
But the main answer is that Garbage Collection just works unless you mess around with it!
但主要的答案是垃圾收集只是有效,除非你把它搞砸了!
回答by Booji Boy
You can't really force a GC to clean up an object when you want, although there are ways to force it to run, nothing says it's clean up the all the object you want/expect. It's best to call dispose in a try catch ex finally dispose end try (VB.NET rulz) way. But Dispose is for cleaning up system resources (memory, handles, db connections, etc. allocated by the object in deterministic way. Dispose doesn't (and can't) clean up the memory used by the object itself, only the the GC can do that.
您不能真正强制 GC 在需要时清理对象,尽管有多种方法可以强制它运行,但没有说它会清理您想要/期望的所有对象。最好在 try catch ex finally dispose end try (VB.NET rulz) 方式中调用 dispose。但是 Dispose 用于清理系统资源(内存、句柄、db 连接等,由对象以确定性方式分配。Dispose 不会(也不能)清理对象本身使用的内存,只有 GC可以这样做。
回答by Greg Hurlman
This articlehas a pretty straightforward walkthrough. However, havingto call the GC instead of letting it take its natural course is generally a sign of bad design/memory management, especiallyif no limited resources are being consumed (connections, handles, anything else that typically leads to implementing IDisposable).
这篇文章有一个非常简单的演练。然而,必须调用 GC 而不是让它自然而然地进行通常是设计/内存管理不佳的标志,尤其是在没有消耗有限资源(连接、句柄、其他任何通常会导致实现 IDisposable 的)的情况下。
What's causing you to need to do this?
是什么让你需要这样做?

