我有访问修改关闭了字符串变量的警告。访问修改的关闭警告是否对字符串变量有效?
foreach (string s in splits)
{
regexes.Where(x => x.Pattern.Contains(s));
}
离开代码的方式是否安全?我认为使用lambda创建的委托将按值接收字符串,因为字符串是不可变的,每个新的“s”都会偏向不同的内存。
感谢
我有访问修改关闭了字符串变量的警告。访问修改的关闭警告是否对字符串变量有效?
foreach (string s in splits)
{
regexes.Where(x => x.Pattern.Contains(s));
}
离开代码的方式是否安全?我认为使用lambda创建的委托将按值接收字符串,因为字符串是不可变的,每个新的“s”都会偏向不同的内存。
感谢
我认为使用lambda创建的委托会按值接收字符串,因为字符串是不可变的,每个新的“s”都会偏向不同的内存。
创建委托并不是评估的变量。这是对关闭整点:他们收,较变量。所以,你所有的lambda会捕获相同的变量s
,这可能不是你想要的。如果它影响你的代码,则取决于评估lambda表达式的时间:如果Where
的调用已经“执行”了lambda表达式(然后将它抛出),那么你应该没问题。如果您的regexes
对象存储了lambdas并稍后使用它们,那么您遇到了麻烦。
因此,为了安全起见,首先将该值复制到循环内部的局部变量中。
在这种情况下,因为你没有使用委托在一个地方外循环它不会伤害你的。当然,你是不是真的做任何事情有用在本例中,因此目前还不清楚,如果这“代表”为您实际代码。
线程和延迟回调会遭受虽然,所以是的,它是(在某种程度上)有效。如果不确定,修复:
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));
}
谢谢,这实际上是我想要做的。有没有更好的方法来建立where子句? – Marek 2011-03-17 10:10:28
@marek - 我会更新... – 2011-03-17 10:12:21
看起来并不安全,我通常尽可能避免警告,因为它们经常表明潜在的问题。
谷歌搜索"access to modified closure"
带来了一些看似相关的命中,包括#2,Linq: Beware of the 'Access to modified closure' demon,你一定要在仔细观察。
下面是一个简单的例子,证明这对字符串是不安全的,不可变或不可变。
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表达式,因为大多是拉姆达的整个生命周期是在foreach的范围之内。
[Access to Modified Closure]的可能重复(http://stackoverflow.com/questions/235455/access-to-modified-closure) – Jon 2011-03-17 09:56:44