簡體   English   中英

對於收益率返回方法,是否可能有一個“最終”代碼塊?

[英]Is it possible to have a 'finally' code-block for yield-return methods?

背景

嗨,大家好。 我有一個稱為BaseRecordFetcher<TEntity>的抽象類,它有一個方法從子類中獲取read / sort / translate / move-next方法,並且yield以模型實體的形式返回結果。

當我讀取多個數據行時,它會正確地為每個實體yield return ,然后在do...while之后到達Trace消息, do...while不會出現任何問題。

問題

但是,我注意到,當我在集合上使用IEnumerable.FirstOrDefault()時,系統假定不再需要任何收益率回報,並且它不會完成該方法的執行

除了返回多少記錄的跟蹤輸出外,我對這種行為沒有太大的疑問,但是這讓我想到:“如果我確實需要一些……讓我們將其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塊,是的,它們旨在處理這種確切的情況。

IEnumerator<T>實現IDisposable 當編譯器將迭代器塊轉換為實現時,枚舉器的Dispose方法將基於應處理該枚舉器的當前位置來執行應執行的所有finally塊。

這意味着只要迭代IEnumerator確保始終處置其枚舉數,就可以確保您的finally塊將運行。

還要注意, using塊將被轉換為try/finally塊,因此基本上可以像迭代器塊中希望的那樣工作。 當需要處理迭代器時,它們將清理給定的資源。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM