Problem
string [] files = new string[2];
files[0] = "ThinkFarAhead.Example.Settings.Configuration_Local.xml";
files[1] = "ThinkFarAhead.Example.Settings.Configuration_Global.xml";
//Resharper complains this is an "access to modified closure"
for (int i = 0; i < files.Length; i++ )
{
// Resharper disable AccessToModifiedClosure
if(Array.Exists(Assembly.GetExecutingAssembly().GetManifestResourceNames(),
delegate(string name) { return name.Equals(files[i]); }))
return Assembly.GetExecutingAssembly().GetManifestResourceStream(files[i]);
// ReSharper restore AccessToModifiedClosure
}
Although the above appears to work, ReSharper warns that it is “access to modified closure.” Is there anyone who can give some light on this?
(here’s where we’ll go with this)
Asked by Vyas Bharghava
Solution #1
It’s fine in this example because the delegate is being executed within the loop.
However, if you save the delegate and use it later, you’ll notice that all of the delegates raise exceptions when attempting to access files[i] because they’re capturing the variable I rather than its value at the time of the delegate’s creation.
In short, it’s something to be aware of as a possible trap, but it won’t harm you in this circumstance.
A more complex example with unexpected outcomes can be found at the bottom of this page.
Answered by Jon Skeet
Solution #2
I realize this is an old question, but I’ve been studying closures recently and thought a code sample could be helpful. The compiler creates a class that represents a lexical closure for your function call behind the scenes. It most likely looks like this:
private sealed class Closure
{
public string[] files;
public int i;
public bool YourAnonymousMethod(string name)
{
return name.Equals(this.files[this.i]);
}
}
As previously stated, your code works because the predicates are called just after they are created. The compiler will produce anything along the lines of:
private string Works()
{
var closure = new Closure();
closure.files = new string[3];
closure.files[0] = "notfoo";
closure.files[1] = "bar";
closure.files[2] = "notbaz";
var arrayToSearch = new string[] { "foo", "bar", "baz" };
//this works, because the predicates are being executed during the loop
for (closure.i = 0; closure.i < closure.files.Length; closure.i++)
{
if (Array.Exists(arrayToSearch, closure.YourAnonymousMethod))
return closure.files[closure.i];
}
return null;
}
If you save and then invoke the predicates, you’ll notice that each call to the predicates is actually calling the same method on the same instance of the closure class, and so uses the same value for i.
Answered by gerrard00
Solution #3
Because the anonymous delegate function has captured “files,” it is a captured outer variable. The anonymous delegate function extends its lifetime.
MSDN’s Outer Variables
Answered by chris hu
Post is based on https://stackoverflow.com/questions/235455/access-to-modified-closure