C# 当foreach将中断时执行一些操作
我正在尝试为我的一个类实现IEnumerable接口:C# 当foreach将中断时执行一些操作,c#,ienumerable,C#,Ienumerable,我正在尝试为我的一个类实现IEnumerable接口: public class NdbScanTableTuple<TKey,TRow> : NdbTableTuple<TKey,TRow>,IEnumerable<TRow> { public IEnumerator<TRow> GetEnumerator() { yieldTransaction = StartTransaction(); NdbS
public class NdbScanTableTuple<TKey,TRow> : NdbTableTuple<TKey,TRow>,IEnumerable<TRow>
{
public IEnumerator<TRow> GetEnumerator()
{
yieldTransaction = StartTransaction();
NdbScanOperation scanPub = yieldTransaction.ScanTable(m_scanRow.NdbRecordValue, NdbOperation.LockMode.LM_Read);
//some error checking in the middle... and than the loop
TRow tmpRes;
while (scanPub.nextResult<TRow>(ref m_scanRow.ManagedRow) == 0)
{
tmpRes = m_scanRow.GetValue();
yield return tmpRes;
}
yieldTransaction.Close();
}
public void CloseYieldedTransaction()
{
yieldTransaction.Close();
}
}
这是因为我必须在退出循环时关闭事务。
现在我的问题是:当我提前终止foreach循环时,有一种方法可以执行yieldTransaction.Close()
,而无需显式调用closeyieldtransaction()
?而不是使用函数样式,您应该实际创建一个(可能是嵌套的)类,该类实现接口并包含执行迭代所需的资源(如事务对象)
然后,该类可以包含事务对象,并从迭代器的Dispose
方法中关闭它,该方法在foreach
终止时(正常或异常)自动调用
这也将使您的设计更简洁,因为目前,您似乎将事务存储为类的一个成员,这使得您当前的类对于多个线程进行枚举(甚至对于单个线程获取多个枚举数)是不安全的。您应该实际创建一个(可能是嵌套的)类,该类实现接口并包含执行迭代所需的资源(例如事务对象)
然后,该类可以包含事务对象,并从迭代器的Dispose
方法中关闭它,该方法在foreach
终止时(正常或异常)自动调用
这也将使您的设计更简洁,因为目前,您似乎将事务存储为类的一个成员,这使得您当前的类对于多个线程进行枚举(甚至对于单个线程获取多个枚举器)是不安全的.您不知道枚举已停止。该方法不再被调用,但您无法知道这一点 确保事务关闭的一种方法是在
using
语句中使用IDisposable
,并在本地资源所在的位置使用适当的终结器(最有可能是套接字-您不必处理它,它已经被处理)是的。棘手的部分是你真的不能依赖任何托管资源仍然存在于终结器中,所以你有一个问题
当您使用IDisposable
时,foreach
将在超出范围时调用Dispose
,这很好。当然,当您不使用foreach
时,许多自动化的东西都会崩溃
现在,yield return
拥有了自己的IEnumerator
。然而,它确实能正确处理处置。你唯一要做的就是你应该经常做的事情:使用try-finally
:
public IEnumerator<TRow> GetEnumerator()
{
var yieldTransaction = StartTransaction();
try
{
NdbScanOperation scanPub = yieldTransaction.ScanTable
(m_scanRow.NdbRecordValue, NdbOperation.LockMode.LM_Read);
//some error checking in the middle... and than the loop
TRow tmpRes;
while (scanPub.nextResult<TRow>(ref m_scanRow.ManagedRow) == 0)
{
tmpRes = m_scanRow.GetValue();
yield return tmpRes;
}
}
finally
{
yieldTransaction.Close();
}
}
public IEnumerator GetEnumerator()
{
var yieldTransaction=StartTransaction();
尝试
{
NdbScanOperation scanPub=yieldTransaction.ScanTable
(m_scanRow.NdbRecordValue、ndbooperation.LockMode.LM_Read);
//在中间和循环中进行一些错误检查。
TROWTMPRES;
while(scanPub.nextResult(ref m_scanRow.ManagedRow)==0)
{
tmpRes=m_scanRow.GetValue();
收益率;
}
}
最后
{
yieldTransaction.Close();
}
}
学习使用
finally
-您正在执行的每个托管终结都应该在finally
中,这对于正确的深入异常处理非常关键。您不知道枚举已停止。不再调用该方法,但您不知道这一点
确保事务关闭的一种方法是在using
语句中使用IDisposable
,并在本地资源所在的位置使用适当的终结器(最有可能是套接字-您不必处理它,它已经被处理)是的。棘手的部分是你真的不能依赖任何托管资源仍然存在于终结器中,所以你有一个问题
当您使用IDisposable
时,foreach
将在超出范围时调用Dispose
,这很好。当然,当您不使用foreach
时,许多自动化的东西都会崩溃
现在,yield return
拥有了自己的IEnumerator
。然而,它确实能正确处理处置。你唯一要做的就是你应该经常做的事情:使用try-finally
:
public IEnumerator<TRow> GetEnumerator()
{
var yieldTransaction = StartTransaction();
try
{
NdbScanOperation scanPub = yieldTransaction.ScanTable
(m_scanRow.NdbRecordValue, NdbOperation.LockMode.LM_Read);
//some error checking in the middle... and than the loop
TRow tmpRes;
while (scanPub.nextResult<TRow>(ref m_scanRow.ManagedRow) == 0)
{
tmpRes = m_scanRow.GetValue();
yield return tmpRes;
}
}
finally
{
yieldTransaction.Close();
}
}
public IEnumerator GetEnumerator()
{
var yieldTransaction=StartTransaction();
尝试
{
NdbScanOperation scanPub=yieldTransaction.ScanTable
(m_scanRow.NdbRecordValue、ndbooperation.LockMode.LM_Read);
//在中间和循环中进行一些错误检查。
TROWTMPRES;
while(scanPub.nextResult(ref m_scanRow.ManagedRow)==0)
{
tmpRes=m_scanRow.GetValue();
收益率;
}
}
最后
{
yieldTransaction.Close();
}
}
学习使用
finally
-您正在执行的每个托管终结都应该在finally
中,这对于正确的深入异常处理非常关键。您需要实现IEnumerator
,如下所示:
public class NdbScanTableTuple<TKey,TRow> : IEnumerable<TRow>
{
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<TRow> GetEnumerator()
{
return new Enumerator<TRow>();
}
private class Enumerator<T> : IEnumerator<T>
{
object IEnumerator.Current { get { return this.Current; } }
public T Current { get { return tmpRes; } }
public void Dispose()
{
yieldTransaction.Close();
}
public bool MoveNext()
{
}
public void Reset()
{
}
}
}
public类NdbScanTableTuple:IEnumerable
{
IEnumerator IEnumerable.GetEnumerator()
{
返回此.GetEnumerator();
}
公共IEnumerator GetEnumerator()
{
返回新的枚举数();
}
私有类枚举器:IEnumerator
{
对象IEnumerator.Current{get{返回this.Current;}
公共T当前{get{return tmpRes;}
公共空间处置()
{
yieldTransaction.Close();
}
公共图书馆
{
}
公共无效重置()
{
}
}
}
(我给你们留下了一些细节。)
这就是它不起作用的原因
您会注意到Di