简体   繁体   English

访问修改后的闭包

[英]Access to modified Closure

Will this fail?这会失败吗? Resharper reports this as an instance of "Access to modified Closure" Will the lambda be triggered for every value? Resharper 将此报告为“访问修改后的闭包”的实例 是否会针对每个值触发 lambda? Is the iterator generating the complete list of all interval values in this before the line that changes first runs?迭代器是否在first运行更改的行之前生成了this中所有间隔值的完整列表? Or is the line first = itvl;或者是first = itvl; running for reach iteration, and that changed value of first used for subsequent iterations??运行到达迭代,并且改变的值first用于后续迭代??

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

NOTE.笔记。 HourInterval is a value-type struct that represents each one-hour-long calendar hour... and this is an IEnumerable collection of HourInterval objects HourInterval是一个值类型结构,表示每个一小时的日历小时...... this是一个IEnumerableHourInterval对象集合

EDIT:编辑:

The above is what Resharper suggested to convert to a LINQ expression from the below foreach construction...以上是 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;
        }
    }

OK, this is a bit of a mess.好吧,这有点乱。

First off, it is a poor programming practice to use the same variable name in two slightly inconsistent ways in the same code.首先,在同一代码中以两种稍微不一致的方式使用相同的变量名是一种糟糕的编程习惯。 It's very confusing.这很令人困惑。 Frankly, I would prefer this to be illegal;坦率地说,我宁愿这是非法的。 the reason that it is not illegal is a bit complicated;不违法的原因有点复杂; see http://blogs.msdn.com/b/ericlippert/archive/2009/11/05/simple-names-are-not-so-simple-part-two.aspx for details.有关详细信息,请参阅http://blogs.msdn.com/b/ericlippert/archive/2009/11/05/simple-names-are-not-so-simple-part-two.aspx

Let's get rid of that problem:让我们摆脱这个问题:

var first = HourInterval.Make(DateTime.MaxValue);
foreach (var itvl in this.Where(x => x < first))
  first = itvl;

Now, the next question is: is Resharper correct to note that this is an access to a modified closure?现在,下一个问题是:Resharper 是否正确地指出这是对修改后闭包的访问? Yes, Resharper is correct;是的,Resharper 是正确的; you are modifying a closed-over variable of a lambda that will be called repeatedly.您正在修改将被重复调用的 lambda 的封闭变量。 Resharper is noting that this is dangerous because Resharper does not know what "Where" does. Resharper 指出这是危险的,因为 Resharper 不知道“在哪里”做了什么。 For all Resharper knows, "Where" is caching every predicate it gets and is saving it up to execute later, in the mistaken belief that each predicate will do something different. Resharper 都知道,“在哪里”正在缓存它获得的每个谓词,并将其保存以供以后执行,错误地认为每个谓词都会做不同的事情。 In fact each predicate is the same, because each predicate is closed over the same variable, not closed over different variables.实际上每个谓词都是一样的,因为每个谓词都是对同一个变量封闭的,而不是对不同变量的封闭。

Clearly no sensible implementation of "Where" will do that.显然,“Where”的任何明智实施都不会做到这一点。 But Resharper doesn't know that.但 Resharper 并不知道这一点。

The next question is: is this a sensible thing to do?下一个问题是:这样做是否明智? No. This is a terribly unidiomatic and confusing way to implement "Min", by modifying the closed-over variable of a predicate to "Where".不,通过将谓词的封闭变量修改为“Where”,这是实现“Min”的一种非常单一且令人困惑的方式。 If you want to write Min, just write 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;
}

There, that returns the earliest date in the sequence, or null if the sequence is empty.在那里,返回序列中最早的日期,如果序列为空,则返回 null。 No messing about with Where and predicates and mutated closures and all that nonsense: write the code to be straightforward and obviously correct.不要搞乱 Where 和谓词以及变异的闭包和所有那些废话:编写代码要简单明了且明显正确。

Your code should work, but that's an unnecessarily complicated way to do it.您的代码应该可以工作,但这是一种不必要的复杂方法。

Try尝试

this.Aggregate((min, next) => next < min ? next : min);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM