You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为含yield的StreamReader迭代器方法添加异常处理?

问题分析
  • 含yield return的迭代器方法中,编译器禁止在带catch子句的try块内使用yield return,会触发CS1626错误;
  • 迭代器方法不能直接返回null,只能通过yield return生成元素或终止迭代,否则触发CS1622错误;
  • 需求是保留迭代器延迟加载特性的同时,添加异常日志记录,并支持调用方实现重试逻辑。
解决方案

核心思路:

  1. 将可能抛出异常的操作(文件打开、单行读取)单独包裹在try-catch块中,确保yield return不处于带catch的try块范围内;
  2. 方法内捕获异常时记录日志,再重新抛出异常,将重试逻辑交给调用方处理(符合单一职责原则);
  3. 调用方通过循环捕获异常,实现指定次数的重试,每次重试重新触发整个文件读取流程。
代码实现

改进后的ReadAsLines方法

static IEnumerable<string> ReadAsLines(string filename)
{
    // 处理文件打开时的异常
    StreamReader reader;
    try
    {
        reader = new StreamReader(filename);
    }
    catch (IOException ex)
    {
        Console.WriteLine($"[错误] 打开文件 {filename} 失败: {ex.Message}");
        throw; // 重新抛出异常,让调用方处理重试
    }

    using (reader)
    {
        while (!reader.EndOfStream)
        {
            string line;
            // 处理单行读取时的异常
            try
            {
                line = reader.ReadLine();
            }
            catch (IOException ex)
            {
                Console.WriteLine($"[错误] 读取文件 {filename} 行失败: {ex.Message}");
                throw; // 重新抛出异常
            }

            yield return line;
        }
    }
}

调用方重试逻辑示例

const int MaxRetryCount = 3;
int currentRetry = 0;
bool isReadSuccess = false;

while (currentRetry < MaxRetryCount && !isReadSuccess)
{
    try
    {
        foreach (var line in ReadAsLines("target.txt"))
        {
            // 调用分隔符检测方法处理行数据
            if (IsValidSeparator(line))
            {
                Console.WriteLine($"找到有效分隔符行: {line}");
                // 执行后续业务逻辑
            }
        }
        isReadSuccess = true;
        Console.WriteLine("文件读取完成");
    }
    catch (IOException ex)
    {
        currentRetry++;
        Console.WriteLine($"[重试] 第 {currentRetry} 次尝试,异常信息: {ex.Message}");
        // 重试前延迟1秒,避免频繁重试
        System.Threading.Thread.Sleep(1000);
    }
}

if (!isReadSuccess)
{
    Console.WriteLine($"[失败] 已重试 {MaxRetryCount} 次,仍无法读取文件");
}

// 分隔符检测方法
static bool IsValidSeparator(string line)
{
    return !string.IsNullOrWhiteSpace(line) && line.StartsWith("---");
}
关键说明
  • 规避了yield return处于带catch的try块内的情况,解决了CS1626错误;
  • 迭代器方法仅负责日志记录和抛出异常,重试逻辑由调用方实现,职责划分清晰;
  • 每次重试都会重新打开文件并从头读取,确保数据完整性(若需断点续读需额外实现状态记录)。

内容的提问来源于stack exchange,提问作者Michele

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 15:22:41