C # 2008
我已经在这方面工作了一段时间,但我仍然对在代码中使用finalize和dispose方法感到困惑。我的问题如下:
I know that we only need a finalizer while disposing unmanaged resources. However, if there are managed resources that make calls to unmanaged resources, would it still need to implement a finalizer?
However, if I develop a class that doesn't use any unmanaged resource - directly or indirectly, should I implement the IDisposable to allow the clients of that class to use the 'using statement'?
Would it be feasible to implement IDisposable just to enable clients of your class to use the using statement?
using(myClass objClass = new myClass())
{
// Do stuff here
}
I have developed this simple code below to demonstrate the Finalize/dispose use:
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)
{
// Do work here
}
// Dispose of the NoGateway object
public void Dispose()
{
wc.DownloadStringCompleted -= wc_DownloadStringCompleted;
wc.Dispose();
GC.SuppressFinalize(this);
}
}
关于源代码的问题:
Here I have not added the finalizer, and normally the finalizer will be called by the GC, and the finalizer will call the Dispose. As I don't have the finalizer, when do I call the Dispose method? Is it the client of the class that has to call it?
So my class in the example is called NoGateway and the client could use and dispose of the class like this:
using(NoGateway objNoGateway = new NoGateway())
{
// Do stuff here
}
Would the Dispose method be automatically called when execution reaches the end of the using block, or does the client have to manually call the dispose method? i.e.
NoGateway objNoGateway = new NoGateway();
// Do stuff with object
objNoGateway.Dispose(); // finished with it
I am using the WebClient class in my NoGateway class. Because WebClient implements the IDisposable interface, does this mean that WebClient indirectly uses unmanaged resources? Is there a hard and fast rule to follow this? How do I know that a class uses unmanaged resources?
我同意pm100的观点(我应该在之前的文章中明确地说明这一点)。
除非需要,否则永远不要在类中实现IDisposable。具体来说,大约有5次你需要/应该实现IDisposable:
Your class explicitly contains (i.e. not via inheritance) any managed resources which implement IDisposable and should be cleaned up once your class is no longer used. For example, if your class contains an instance of a Stream, DbCommand, DataTable, etc.
Your class explicitly contains any managed resources which implement a Close() method - e.g. IDataReader, IDbConnection, etc. Note that some of these classes do implement IDisposable by having Dispose() as well as a Close() method.
Your class explicitly contains an unmanaged resource - e.g. a COM object, pointers (yes, you can use pointers in managed C# but they must be declared in 'unsafe' blocks, etc.
In the case of unmanaged resources, you should also make sure to call System.Runtime.InteropServices.Marshal.ReleaseComObject() on the RCW. Even though the RCW is, in theory, a managed wrapper, there is still reference counting going on under the covers.
If your class subscribes to events using strong references. You need to unregister/detach yourself from the events. Always to make sure these are not null first before trying to unregister/detach them!.
Your class contains any combination of the above...
对于使用COM对象并且必须使用Marshal.ReleaseComObject(),推荐的替代方法是使用System.Runtime.InteropServices.SafeHandle类。
BCL(基类库团队)在这里有一篇关于它的很好的博客文章http://blogs.msdn.com/bclteam/archive/2005/03/16/396900.aspx
一个非常重要的注意事项是,如果你正在使用WCF并清理资源,你几乎总是应该避免使用'using'块。有很多博客和MSDN上的文章都在解释为什么这是一个坏主意。我也在这里发布了关于它的帖子-不要在WCF代理中使用'using()'
没有人回答你是否应该实现IDisposable的问题,即使你不需要它。
简单的回答:不
长一点的回答:
这将允许你的类的消费者使用“using”。我想问的问题是,他们为什么要这么做?大多数开发者不会使用“使用”,除非他们知道他们必须这么做——他们是怎么知道的。要么
很明显,从经验来看(例如,一个套接字类)
它的记录
他们很谨慎,可以看到类实现了IDisposable
因此,通过实现IDisposable,你可以告诉开发人员(至少是一些开发人员)这个类封装了一些必须发布的东西。他们会使用“using”——但在其他情况下,使用是不可能的(对象的作用域不是本地的);他们将不得不开始担心在其他情况下对象的生命周期-我肯定会担心。但这是不必要的
你实现Idisposable,让他们使用使用,但他们不会使用使用,除非你告诉他们。
所以不要这么做
使用lambdas代替IDisposable。
我从来没有对使用/IDisposable这个想法感到兴奋。问题是它要求调用者:
知道他们必须使用IDisposable
记住使用“using”。
我新的首选方法是使用工厂方法和lambda代替
假设我想用SqlConnection(应该用using包装的东西)做一些事情。通常你会这么做
using (Var conn = Factory.MakeConnection())
{
conn.Query(....);
}
新方法
Factory.DoWithConnection((conn)=>
{
conn.Query(...);
}
在第一种情况下,调用者不能简单地使用using语法。在第二种情况下,用户没有选择。没有创建SqlConnection对象的方法,调用者必须调用DoWithConnection。
DoWithConnection看起来像这样
void DoWithConnection(Action<SqlConnection> action)
{
using (var conn = MakeConnection())
{
action(conn);
}
}
MakeConnection现在是私有的