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

C#扩展方法如何不枚举无限序列即可完成参数合法性校验

结论

需求可以实现,但你当前的代码无法满足要求,需要调整扩展方法的结构。

问题原因

C#中包含yield return语法的方法属于迭代器方法,这类方法的执行是延迟的:

  • 直接调用方法时不会执行方法体内的任何代码,仅返回一个实现了IEnumerable的状态机对象
  • 只有当你主动枚举返回值(调用MoveNext())时,才会真正执行方法内部的逻辑

你当前把参数校验的if逻辑和迭代器逻辑写在同一个方法里,所以调用infiniteSeq.Smooth(-1)的时候不会触发参数校验,测试会失败;如果强制枚举返回值又会触发对infiniteSeq的遍历,违反你的需求。

修复方案

把参数校验和迭代器逻辑拆分为两个独立的方法,参数校验放在外层普通方法中立刻执行,迭代器逻辑放到内层嵌套的迭代器方法中即可,修改后的代码如下:

public static IEnumerable<double> Smooth(this IEnumerable<double> s, int N)
{
    // 参数校验放在外层普通方法,调用时立刻执行
    if (N < 0) throw new ArgumentOutOfRangeException(nameof(N), "Is negative");
    if (s is null) throw new ArgumentNullException(nameof(s), "is null");

    // 迭代器逻辑放到内层方法,只有枚举的时候才会执行
    return SmoothCore(s, N);
}

private static IEnumerable<double> SmoothCore(IEnumerable<double> s, int N)
{
    while (true)
    {
        List<double> buffer = new List<double>();
        using (var seqEnumerator = s.GetEnumerator())
        {
            int index = 0;
            while (seqEnumerator.MoveNext())
            {
                buffer.Add(seqEnumerator.Current);
                    
                //Enough items to start Smoothing
                if (buffer.Count >= N*2)
                {
                    List<double> elementForAvg;
                    try
                    {
                        int startIndex = (index-N<0) ? 0 : index-N;
                        int endIndex = index+N;
                        
                        elementForAvg = buffer.GetRange(startIndex,endIndex);
                    }
                    catch (Exception e)
                    {
                        if (e is ArgumentException)
                            throw new FiniteSourceException();
                        
                        throw;
                    }
                    
                    yield return AvgCalculator(elementForAvg);
                    index++;
                }
            }
            throw new FiniteSourceException();
        }
    }
}

效果说明

修改后你原有的测试代码可以直接通过:

Assert.That(()=> infiniteSeq.Smooth(-1), Throws.TypeOf<ArgumentOutOfRangeException>());

调用Smooth方法时会立刻执行参数校验抛出异常,完全不会进入迭代器逻辑,也不会对infiniteSeq做任何枚举操作,符合你的全部要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 20:27:03