gpt4 book ai didi

c# - 是否可以为 yield-return 方法设置 'finally' 代码块?

转载 作者:太空宇宙 更新时间:2023-11-03 21:34:42 24 4
gpt4 key购买 nike

背景

大家好。我有一个名为 BaseRecordFetcher<TEntity> 的抽象类它有一个方法从子类中获取读取/排序/翻译/移动下一个方法,并且 yield 将结果作为模型实体返回。

当我读取多个数据行时,它会正确执行 yield return对于每个实体,然后在 do...while 之后到达 Trace 消息没有任何问题。

问题

但是我注意到当我使用 IEnumerable.FirstOrDefault() 时在集合上,系统假定不再需要 yield 返回,并且它不会完成此方法的执行!

除了关于返回了多少记录的跟踪输出之外,我对这种行为没有太多问题,但这让我开始思考:“如果我确实需要一些……我们称之为finally 代码?”

问题

有没有办法始终确保系统在 yield return 之后运行一些后处理代码? ?

代码

/// <summary>
/// Retrieve translated entities from the database. The methods used to do
/// this are specified from the child class as parameters (i.e. Action or
/// Func delegates).
/// </summary>
/// <param name="loadSubsetFunc">
/// Specify how to load a set of database records. Return boolean
/// confirmation that records were found.
/// </param>
/// <param name="preIterationAction">
/// Specify what should happen to sort the results.
/// </param>
/// <param name="translateRowFunc">
/// Specify how a database record should translate to a model entity.
/// Return the new entity.
/// </param>
/// <param name="moveNextFunc">
/// Specify how the database row pointer should move on. Return FALSE on a
/// call to the final row.
/// </param>
/// <returns>
/// A set of translated entities from the database.
/// </returns>
/// <example><code>
///
/// return base.FetchRecords(
/// _dOOdad.LoadFacilitySites,
/// () => _dOOdad.Sort = _dOOdad.GetAutoKeyColumn(),
/// () =>
/// {
/// var entity = new FacilitySite();
/// return entity.PopulateLookupEntity(
/// _dOOdad.CurrentRow.ItemArray);
/// },
/// _dOOdad.MoveNext);
///
/// </code></example>
protected virtual IEnumerable<TEntity> FetchRecords(
Func<bool> loadSubsetFunc, Action preIterationAction,
Func<TEntity> translateRowFunc, Func<bool> moveNextFunc)
{
// If records are found, sort them and return set of entities
if (loadSubsetFunc())
{
Trace.WriteLine(string.Format(
"# FOUND one or more records: Returning {0}(s) as a set.",
typeof(TEntity).Name));

int recordCount = 0;

preIterationAction();

do
{
recordCount++;
var entity = translateRowFunc();
yield return entity;
}
while (moveNextFunc());

// This code never gets reached if FirstOrDefault() is used on the set,
// because the system will assume no more enities need to be returned
Trace.WriteLine(string.Format(
"# FINISHED returning records: {0} {1}(s) returned as a set.",
recordCount, typeof(TEntity).Name));
}
else
{
Trace.WriteLine(string.Format(
"# ZERO records found: Returning an empty set of {0}.",
typeof(TEntity).Name));
}
}

编辑(添加解决方案;谢谢@Servy 和@BenRobinson):

try
{
do
{
recordCount++;
var entity = translateRowFunc();
yield return entity;
}
while (moveNextFunc());
}
finally
{
// This code always executes, even when you use FirstOrDefault() on the set.
Trace.WriteLine(string.Format(
"# FINISHED returning records: {0} {1}(s) returned as a set.",
recordCount, typeof(TEntity).Name));
}

最佳答案

是的,你可以提供finally迭代器 block 中的 block ,是的,它们旨在处理这种情况。

IEnumerator<T>工具 IDisposable .当编译器将迭代器 block 转换为实现时 Dispose枚举器的方法将执行任何应根据枚举器当前所在位置执行的 finally block 。

这意味着只要谁在迭代IEnumerator确保始终处理他们的枚举器,你可以确定你的 finally block 将运行。

另请注意 using block 将被转换为 try/finally block ,因此基本上可以像在迭代器 block 中希望的那样工作。如果需要,它们将在处理迭代器时清理给定的资源。

关于c# - 是否可以为 yield-return 方法设置 'finally' 代码块?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22330951/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com