访问修改后的Closure

Cha*_*ana 1 .net c# lambda

这会失败吗?Resharper将此报告为"访问已修改的闭包"的实例是否会为每个值触发lambda?迭代器是否在this更改first运行的行之前生成所有间隔值的完整列表?或者是first = itvl; 为了达到迭代而运行的行,并且改变了first用于后续迭代的值?

 public HourInterval FirstInterval
    {
        get
        {
            var first = HourInterval.Make(DateTime.MaxValue);
            foreach (var itvl in this.Where
                        (itvl => itvl < first))
                first = itvl;
            return first;
        }
    }
Run Code Online (Sandbox Code Playgroud)

注意. HourInterval是一个值类型结构,表示每个一小时的日历时间......并且this是一个对象的IEnumerable集合HourInterval

编辑:

以上是Resharper建议从以下foreach构造转换为LINQ表达式的内容......

    public HourInterval FirstInterval
    {
        get
        {
            var first = HourInterval.Make(DateTime.MaxValue);
            foreach (var itvl in this)
               if(itvl < first)
                  first = itvl;
            return first;
        }
    }
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 14

好的,这有点乱.

首先,在同一代码中以两种稍微不一致的方式使用相同的变量名是一种糟糕的编程习惯.这很令人困惑.坦率地说,我宁愿这是非法的; 它不违法的原因有点复杂; 有关详细信息,请参阅http://blogs.msdn.com/b/ericlippert/archive/2009/11/05/simple-names-are-not-so-simple-part-two.aspx.

让我们摆脱这个问题:

var first = HourInterval.Make(DateTime.MaxValue);
foreach (var itvl in this.Where(x => x < first))
  first = itvl;
Run Code Online (Sandbox Code Playgroud)

现在,接下来的问题是:Resharper是否正确注意到这是对已修改闭包的访问?是的,Resharper是正确的; 您正在修改将重复调用的lambda的已关闭变量.Resharper注意到这是危险的,因为Resharper不知道"Where"的作用.对于所有Resharper都知道,"Where"缓存它获得的每个谓词,并将其保存起来以便稍后执行,错误地认为每个谓词都会做出不同的事情.实际上每个谓词都是相同的,因为每个谓词都在同一个变量上关闭,而不是在不同的变量上关闭.

显然,"Where"的合理实施不会那样做.但是Resharper并不知道.

接下来的问题是:这是一件明智的事吗?不.通过将谓词的封闭变量修改为"Where",这是实现"Min"的非常简单且令人困惑的方式.如果你想写Min,只需写Min:

static DateTime? Min(this IEnumerable<DateTime> seq)
{
    DateTime? min = null;
    foreach(DateTime current in seq)
    {
        if (min == null || current < min.Value) 
            min = current;
    }
    return min;
}
Run Code Online (Sandbox Code Playgroud)

在那里,它返回序列中最早的日期,如果序列为空则返回null.没有搞乱Where和谓词和变异的闭包以及所有那些废话:编写代码是直截了当且显然是正确的.


SLa*_*aks 10

您的代码应该可以工作,但这是一种不必要的复杂方法.

尝试

this.Aggregate((min, next) => next < min ? next : min);
Run Code Online (Sandbox Code Playgroud)