我的 IDisposable 是否在我的班级中正确实现或者需要一些更改
我在 C# 2.0 中有以下代码,我正在尝试在我的类中实现 IDisposable。
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using Tridion.ContentManager;
using Tridion.ContentManager.Templating.Assembly;
using Tridion.ContentManager.Templating;
using Tridion.ContentManager.ContentManagement;
using Tridion.ContentManager.ContentManagement.Fields;
using Emirates.Tridion.BuildingBlocks.Base;
using th = my.Tridion.BuildingBlocks.Base.TemplateHelper;
using ut = my.Tridion.BuildingBlocks.Base.Utilities;
using tc = Tridion.ContentManager.CommunicationManagement;
using System.IO;
using System.Globalization;
using System.Threading;
namespace my.BuildingBlocks.Utilities
{
[TcmTemplateTitle("Page Metadata Values")]
public class PageMetaDataValues : TemplateBase, IDisposable
{
private bool m_Disposed = false;
protected bool Disposed
{
get
{
lock (this)
{
return (m_Disposed);
}
}
}
public override void Transform(Engine engine, Package package)
{
Initialize(engine, package);
m_Logger.Info("Start of Page Metadata Values");
tc.Publication pubObject= m_Engine.GetSession().GetObject(m_Publication.Id) as tc.Publication;
if (pubObject != null)
{
Thread.CurrentThread.CurrentCulture = new CultureInfo(ut.RenderPageLocale(pubObject));
}
package.PushItem("PageMetaDataValues", package.CreateStringItem(ContentType.Xml, RenderCurrentPageXML()));
m_Logger.Info("End of Page Metadata Values");
}
private string RenderCurrentPageXML()
{
m_Logger.Info("Rendering the Page Metadata Values");
XmlDocument pageDoc = new XmlDocument();
pageDoc.LoadXml(GetCurrentPageXML(m_Page.Id));
return pageDoc.InnerXml;
}
void IDisposable.Dispose
{
get
{
lock (this)
{
if (m_Disposed == false)
{
Cleanup();
m_Disposed = true;
GC.SuppressFinalize(this);
}
}
}
}
protected virtual void Cleanup()
{
/* do cleanup of unmanaged resources here */
}
#endregion
}
}
请建议我是否正确实现了 IDisposable 接口,或者我需要对上面的代码进行一些更改。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这不是正常的 IDisposable 模式,通常您会做类似的事情:
That's not the normal IDisposable pattern, typically you'd do something more like:
您应该添加一个调用 Cleanup 的终结器。如果有人没有按照应有的方式调用 Dispose,则非托管资源最终将被垃圾收集器清理。
这就是为什么您首先调用 GC.SuppressFinalize(this); 的原因,以确保在正确处置对象的情况下 GC 不会调用您的终结器。
编辑
这意味着您至少需要添加:
但是您的代码中还有一些其他奇怪的情况,例如锁定
this
等。另外,自从您首先添加锁定以来,您是否期望从多个不同的线程中处理同一个对象?You should add a finializer that calls Cleanup to. In case someone don't call Dispose as they should, the unmanaged resources will then eventually be cleaned up by the garbage collector.
That's why you are calling
GC.SuppressFinalize(this);
in the first place, to make sure that the GC does not call your finalizer if the object was disposed properly.EDIT
That means that you at least need to add:
There are however some other strange cases in your code like locking on
this
and so on. Also, are you expecting to dispose the same object from several different threads since you added the locking in the first place?只需更改
为
Just change
to
正如其他人所写的(ControlPower 解决方案是正确的),Dispose 方法是一种方法,而不是属性:-)。
现在我们将看看另一个问题:您正在尝试实现线程安全的 IDisposable 模式。正确地做到这一点是相当复杂的。让我们看看简单的解决方案。你的(经过 Controlpower 的更正)是可以的:-)显然你应该检查每个公共方法/属性开头的
Dispose
属性,如果它是 true,你应该抛出一个ObjectDisposeException< /代码>。更好(更快)的实现是 http://blogs.msdn.com/b/blambert/archive/2009/07/24/a-simple-and-totally-thread-safe-implementation-of-idisposable.aspx
他使用
Interlocked.CompareExchange
而不是lock
。速度更快了。它仍然存在一个问题:如果线程 A 执行方法 A1,同时线程 B 执行对象的 Dispose,则当对象被释放时,线程 A 可能处于中间方法。我会给你第三种解决方案。它使用了ReaderWriterLockSlim。每个公共方法/属性在执行时都会获取读取器锁。 Dispose 在执行时会获取写锁。许多“正常”方法可以同时执行。 Dispose需要在没有其他人执行的时候执行。私有和受保护的方法/属性(不属于接口的一部分)不需要检查已处置状态,因为它们是从公共方法/属性调用的。
As written by others (the ControlPower solution is correct), the Dispose method is a method, not a property :-).
Now we will look at another problem: you are trying to implement a thread safe
IDisposable
pattern. To do it correctly is quite complex. Let's see the naive solution. Yours (with the corrections of Controlpower) is ok :-) Clearly you should check theDisposed
property at the beginning of each public method/property and if it's true, you should throw anObjectDisposedException
. A better (faster) implementation is the one given by http://blogs.msdn.com/b/blambert/archive/2009/07/24/a-simple-and-totally-thread-safe-implementation-of-idisposable.aspxhe uses
Interlocked.CompareExchange
instead oflock
. It's faster.It still suffers from one problem: if Thread A executes method A1 and at the same time Thread B executes a
Dispose
of the object, Thread A could be mid-method when the object is disposed. I'll give you a third solution. It usedReaderWriterLockSlim
. Every public method/property takes a reader lock when it executes. Dispose takes a write lock when it executes. Many "normal" methods can be executed at the same time. Dispose needs to be executed when no one else is executing. Private and protected methods/properties (that aren't part of an interface) don't need to check for the disposed state because they are called from public methods/properties.