繁体   English   中英

对修饰变量的访问权限对字符串变量有效吗?

[英]Is Access to Modified Closure warnings valid for string variable?

我在访问字符串变量的修改后的闭包时发出警告。

foreach (string s in splits)
{
    regexes.Where(x => x.Pattern.Contains(s));
}

以原样保留代码是否安全? 我假设使用lambda创建的委托将按值接收字符串,因为字符串是不可变的,并且每个新的“ s”都将指向不同的内存。

谢谢

在这种情况下,这不会对您造成伤害,因为您不在循环之外的地方使用委托。 当然,您在示例中并没有做任何有用的事情 ,因此尚不清楚这是否代表您的实际代码。

不过,线程和延迟的回调将受到影响,因此是的(在某种程度上)它是有效的。 如果不确定,请修复它:

foreach (string s in splits)
{ 
    var clone = s;
    regexes.Where(x => x.Pattern.Contains(clone));
}

为了明确起见,仅当在foreach循环的正常流程之外使用捕获的变量时,此问题才会受到伤害 直接在循环内部且在同一线程(没有Parallel )上使用时,捕获的变量将始终处于期望值。 任何破裂的东西都会看到随机数据; 通常(但不总是) 最后一个值。

特别要注意的是 ,此“延迟委托”包括诸如在查询上建立Where过滤器之类的事情,因为您会发现它们都使用最后一个值。 以下是不好的:

var query = ...
foreach (string s in splits)
{ // BAD CODE!
    query = query.Where(x => x.Foo.Contains(s));
}

重新进行任何“更好的方式”(评论)...好吧,克隆变量技巧具有工作的优势,但这是一个可爱的技巧-修复了上面的“错误代码!”:

query = splits.Aggregate(query, (tmp, s) => tmp.Where(x => x.Foo.Contains(s)));

我个人认为以下内容更容易理解:

foreach (string s in splits)
{
    var tmp = s;
    query = query.Where(x => x.Foo.Contains(tmp));
}

我假设使用lambda创建的委托将按值接收字符串,因为字符串是不可变的,并且每个新的“ s”都将指向不同的内存。

创建委托不会评估变量。 这就是闭包的全部要点:它们关闭变量 因此,您所有的lambda都将捕获相同的变量s ,这可能不是您想要的。 是否影响代码取决于lambda的评估时间:如果Where的调用已经“执行”了lambda(然后将其丢弃),则应该没事。 如果您的正则regexes对象存储了lambda,并在以后使用它们,则您会遇到麻烦。

因此,为了安全起见,首先将值复制到循环内部的局部变量中。

看起来并不安全,我通常会尽量避免出现警告,因为它们通常表示潜在的问题。

谷歌搜索"access to modified closure"带来了许多看似相关的热门话题,包括#2 Linq:当心您肯定要仔细研究的“访问修改后的闭包”恶魔

这是一个简单的例子,证明这对于不可变的字符串是不安全的。

List<Func<int>> lambdas = new List<Func<int>>();
List<string> strings = new List<string> 
{ "first", "second", "supercalifragilisticexpialidocious" };

foreach (string s in strings)
{
  lambdas.Add(new Func<int>(() => s.Length));
}

Console.WriteLine(lambdas[0]()); //34
Console.WriteLine(lambdas[1]()); //34
Console.WriteLine(lambdas[2]()); //34

但是,除了被LINQ的延迟执行所困扰之外,我真的不认为以这种方式使用lambda并不是问题,因为lambda的整个生命周期都在foreach的范围之内。

暂无
暂无

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

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