访问修改的关闭
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 }
以上似乎工作正常虽然ReSharper抱怨说,这是“访问修改关闭”。 任何人都可以阐明这一点吗?
(这个话题继续下去)
在这种情况下,没关系,因为你实际上是在循环中执行委托。
然而,如果你保存委托并在稍后使用它,你会发现所有委托在尝试访问文件时都会抛出异常[i] – 它们捕获变量 i
而不是代表创作。
总之,这是一个潜在的陷阱,但在这种情况下,它并不会伤害你。
查看本页底部的更复杂的例子,其结果是违反直觉的。
我知道这是一个老问题,但我最近一直在研究闭包,并认为代码示例可能是有用的。 在幕后,编译器正在生成一个表示函数调用的词法闭包的类。 它可能看起来像这样:
private sealed class Closure { public string[] files; public int i; public bool YourAnonymousMethod(string name) { return name.Equals(this.files[this.i]); } }
如上所述,您的函数可以工作,因为谓词在创建之后立即被调用。 编译器会生成如下所示的内容:
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; }
另一方面,如果您要存储并稍后调用谓词,则会看到对谓词的每次调用都将在闭包类的同一个实例上调用相同的方法,因此将使用相同的值一世。
“文件”是一个捕获的外部变量,因为它已被匿名委托函数捕获。 它的生命周期由匿名委托功能扩展。
捕获的外部变量当一个外部变量被匿名函数引用时,外部变量被说成是被匿名函数捕获的。 通常,局部变量的生存期限于执行与之相关的块或语句(局部变量)。 但是,捕获的外部变量的生命周期至少会延长,直到从匿名函数创建的委托或表达式树变为符合垃圾回收的条件。
当局部变量或值参数被匿名函数捕获时,局部变量或参数不再被视为固定变量(固定变量和可移动变量),而是被认为是可移动变量。 因此,任何采用捕获的外部变量地址的不安全代码都必须先使用固定语句来修改变量。 请注意,与未捕获的变量不同,捕获的本地变量可以同时暴露给多个执行线程。