我从阅读MSDN文档中了解到,IDisposable
接口的"主要"用途是清理非托管资源.
对我来说,"非托管"意味着数据库连接,套接字,窗口句柄等等.但是,我已经看到了Dispose()
实现该方法以释放托管资源的代码,这对我来说似乎是多余的,因为垃圾收集器应该照顾那对你而言.
例如:
public class MyCollection : IDisposable
{
private List<String> _theList = new List<String>();
private Dictionary<String, Point> _theDict = new Dictionary<String, Point>();
// Die, clear it up! (free unmanaged resources)
public void Dispose()
{
_theList.clear();
_theDict.clear();
_theList = null;
_theDict = null;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,这是否使得垃圾收集器可以使用的内存MyCollection
比通常更快?
编辑:到目前为止,人们已经发布了一些使用IDisposable清理非托管资源(例如数据库连接和位图)的好例子.但是假设_theList
在上面的代码中包含了一百万个字符串,并且你想现在释放那个内存,而不是等待垃圾收集器.上面的代码会实现吗?
C#2008
我一直在研究这个问题,我仍然对一些问题感到困惑.我的问题如下
我知道如果你处理非托管资源,你只需要一个终结器.但是,如果您使用托管资源来调用非托管资源,您是否仍需要实现终结器?
但是,如果您开发一个不直接或间接使用任何非托管资源的类,您是否可以实现IDisposable
该类,以便您的类的客户端可以使用'using statement'?
是否可以接受实现IDisposable,以便您的类的客户端可以使用using语句?
using(myClass objClass = new myClass())
{
// Do stuff here
}
Run Code Online (Sandbox Code Playgroud)我在下面开发了这个简单的代码来演示Finalize/dispose模式:
public class NoGateway : IDisposable
{
private WebClient wc = null;
public NoGateway()
{
wc = new WebClient();
wc.DownloadStringCompleted += wc_DownloadStringCompleted;
}
// Start the Async call to find if NoGateway is true or false
public void NoGatewayStatus()
{
// Start the Async's download
// Do other work here
wc.DownloadStringAsync(new Uri(www.xxxx.xxx));
}
private void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
// …
Run Code Online (Sandbox Code Playgroud).NET Framework 4.5中的System.Net.Http.HttpClient和System.Net.Http.HttpClientHandler实现了IDisposable(通过System.Net.Http.HttpMessageInvoker).
该using
声明文件说:
通常,当您使用IDisposable对象时,您应该在using语句中声明并实例化它.
这个答案使用了这种模式:
var baseAddress = new Uri("http://example.com");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("foo", "bar"),
new KeyValuePair<string, string>("baz", "bazinga"),
});
cookieContainer.Add(baseAddress, new Cookie("CookieName", "cookie_value"));
var result = client.PostAsync("/test", content).Result;
result.EnsureSuccessStatusCode();
}
Run Code Online (Sandbox Code Playgroud)
但是微软最明显的例子并没有Dispose()
明确地或隐含地调用.例如:
在.NET中,我应该在哪种情况下使用GC.SuppressFinalize()
?
使用这种方法有什么好处?
DataSet和DataTable都实现了IDisposable,因此,通过传统的最佳实践,我应该调用它们的Dispose()方法.
但是,从我到目前为止所读到的,DataSet和DataTable实际上并没有任何非托管资源,因此Dispose()实际上并没有做太多.
另外,我不能只使用,using(DataSet myDataSet...)
因为DataSet有一组DataTables.
所以,为了安全起见,我需要遍历myDataSet.Tables,处理每个DataTable,然后处理DataSet.
那么,在我的所有DataSet和DataTables上调用Dispose()是否值得麻烦?
附录:
对于那些认为应该处理DataSet的人:通常,处理的模式是使用using
or try..finally
,因为你想保证将调用Dispose().
然而,这对于一个集合来说真的很快.例如,如果对Dispose()的一个调用抛出异常,你会怎么做?你吞下它(这是"坏"),以便你可以继续处理下一个元素?
或者,你是否建议我只调用myDataSet.Dispose(),而忘记在myDataSet.Tables中处理DataTables?
就像是:
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
Run Code Online (Sandbox Code Playgroud)
我相信这不是回报声明的合适地方,是吗?
using
在(可能)null对象上使用该语句是否安全?
请考虑以下示例:
class Test {
IDisposable GetObject(string name) {
// returns null if not found
}
void DoSomething() {
using (IDisposable x = GetObject("invalid name")) {
if (x != null) {
// etc...
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
是否保证Dispose
只有在对象不为空时才会被调用,而且我不会得到一个NullReferenceException
?
类如Stream
,StreamReader
,StreamWriter
等工具IDisposable
界面.这意味着,我们可以Dispose()
在这些类的对象上调用方法.他们还定义了一个public
名为的方法Close()
.现在让我感到困惑的是,一旦我完成了对象,我该怎么称呼?如果我同时打电话怎么办?
我目前的代码是这样的:
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(responseStream))
{
using (StreamWriter writer = new StreamWriter(filename))
{
int chunkSize = 1024;
while (!reader.EndOfStream)
{
char[] buffer = new char[chunkSize];
int count = reader.Read(buffer, 0, chunkSize);
if (count != 0)
{
writer.Write(buffer, 0, count);
}
}
writer.Close();
}
reader.Close();
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,我编写了using()
构造,自动调用Dispose()
每个对象的方法.但我也称之为Close()
方法.这样对吗?
请告诉我使用流对象时的最佳做法.:-)
MSDN示例不使用using()
构造,并且调用 …
假设我有一组这样简单的类:
class Bus
{
Driver busDriver = new Driver();
}
class Driver
{
Shoe[] shoes = { new Shoe(), new Shoe() };
}
class Shoe
{
Shoelace lace = new Shoelace();
}
class Shoelace
{
bool tied = false;
}
Run Code Online (Sandbox Code Playgroud)
A Bus
有一个Driver
,Driver
有两个Shoe
,每个Shoe
有一个Shoelace
.一切都很傻.
后来我决定对它进行一些操作Shoelace
可能是多线程的,所以我添加了一个EventWaitHandle
用于与之通信的线程.所以Shoelace
现在看起来像这样:
class Shoelace
{
private AutoResetEvent waitHandle = new AutoResetEvent(false);
bool tied = false;
// ... other stuff .. …
Run Code Online (Sandbox Code Playgroud) .NET IDisposable Pattern 意味着如果您编写终结器并实现IDisposable,则终结器需要显式调用Dispose.这是合乎逻辑的,而且在极少数情况下我总是会做终结器的保证.
但是,如果我这样做会发生什么:
class Foo : IDisposable
{
public void Dispose(){ CloseSomeHandle(); }
}
Run Code Online (Sandbox Code Playgroud)
并且不要实现终结器或任何东西.框架会为我调用Dispose方法吗?
是的,我意识到这听起来很愚蠢,而且所有的逻辑都暗示它不会,但我总是有两件事让我不确定.
几年前有人曾告诉我,事实上它会这样做,而且那个人有"非常了解他们的东西"的良好记录.
编译器/框架根据您实现的接口(例如:foreach,扩展方法,基于属性的序列化等)执行其他"神奇"操作,因此这也可能是"魔术".
虽然我已经阅读了很多关于它的内容,并且有很多暗示的内容,但我从来没有能够找到这个问题的肯定是或否答案.
idisposable ×10
c# ×8
.net ×5
dispose ×4
using ×3
.net-4.5 ×1
dataset ×1
datatable ×1
finalizer ×1
stream ×1
streamreader ×1
streamwriter ×1