我在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接口correclty,或者我需要在上面进行一些代码更改。
答案 0 :(得分:1)
这不是正常的IDisposable pattern,通常你会做更多的事情:
public class DisposableClass : IDisposable
{
~DisposableClass()
{
Dispose(false);
}
private bool disposed = false;
protected bool Disposed
{
get
{
return (disposed);
}
}
public override void Transform(Engine engine, Package package)
{
if( Disposed )
{
throw new ObjectDisposedException();
}
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");
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
disposed = true;
// Clean up all managed resources
}
// Clean up all native resources
}
}
答案 1 :(得分:0)
您应该添加一个调用Cleanup的终结器。如果有人不按预期调用Dispose,那么非托管资源最终将被垃圾收集器清理。
这就是您首先调用GC.SuppressFinalize(this);
的原因,以确保如果对象处理得当,GC不会调用终结器。
修改强>
这意味着您至少需要添加:
public ~PageMetaDataValues(){
Cleanup();
}
然而,您的代码中还存在其他一些奇怪的情况,例如锁定this
等等。此外,您是否期望从几个不同的线程中处置相同的对象,因为您首先添加了锁定?
答案 2 :(得分:0)
只需更改
void IDisposable.Dispose
{
get
{
lock (this)
{
if (m_Disposed == false)
{
Cleanup();
m_Disposed = true;
GC.SuppressFinalize(this);
}
}
}
}
到
public void IDisposable.Dispose()
{
lock (this)
{
if (m_Disposed == false)
{
Cleanup();
m_Disposed = true;
GC.SuppressFinalize(this);
}
}
}
答案 3 :(得分:0)
正如其他人所写的(ControlPower解决方案是正确的),Dispose方法是一种方法,而不是属性: - )。
现在我们将看另一个问题:您正在尝试实现线程安全的IDisposable
模式。要做到这一点非常复杂。让我们看看天真的解决方案。你的(使用Controlpower的更正)是可以的:-)显然你应该检查每个公共方法/属性开头的Disposed
属性,如果是,你应该抛出ObjectDisposedException
。更好(更快)的实现是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。私有和受保护的方法/属性(不是接口的一部分)不需要检查处置状态,因为它们是从公共方法/属性调用的。
class MyClass : IDisposable
{
protected ReaderWriterLockSlim disposeLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
protected bool isDisposed = false;
~MyClass()
{
this.Dispose(false);
}
public int ExamplePublicProperty
{
get
{
disposeLock.EnterReadLock();
try
{
if (isDisposed)
{
throw new ObjectDisposedException(GetType().FullName);
}
// The property
return 0; // What you want to return
}
finally
{
disposeLock.ExitReadLock();
}
}
set
{
disposeLock.EnterReadLock();
try
{
if (isDisposed)
{
throw new ObjectDisposedException(GetType().FullName);
}
// The property
}
finally
{
disposeLock.ExitReadLock();
}
}
}
// The same for private methods
protected int ExampleProtectedProperty
{
// Here we don't need to check for isDisposed
get;
set;
}
public void ExamplePublicMethod()
{
disposeLock.EnterReadLock();
try
{
if (isDisposed)
{
throw new ObjectDisposedException(GetType().FullName);
}
// The method
}
finally
{
disposeLock.ExitReadLock();
}
}
// The same for private methods
protected void ExampleProtectedMethod()
{
// Here we don't need to check for isDisposed
}
#region IDisposable Members
public void Dispose()
{
disposeLock.EnterWriteLock();
try
{
if (isDisposed)
{
return;
}
Dispose(true);
GC.SuppressFinalize(this);
isDisposed = true;
}
finally
{
disposeLock.ExitWriteLock();
}
}
#endregion
protected virtual void Dispose(bool disposing)
{
// do the freeing
}
}