2009-11-06 44 views
34

我有以下代码:ReSharper的警告 - 访问修改关闭

string acctStatus = account.AccountStatus.ToString(); 
if (!SettableStatuses().Any(status => status == acctStatus)) 
    acctStatus = ACCOUNTSTATUS.Pending.ToString(); 

注意account.AccountStatus是类型ACCOUNTSTATUS的枚举。在第二行中,ReSharper向我发出acctStatus的“访问修改的关闭”警告。当我做推荐的操作,复制到本地变量,它修改代码如下:

string acctStatus = realAccount.AccountStatus.ToString(); 
string s = acctStatus; 
if (!SettableStatuses().Any(status => status == s)) 
    acctStatus = ACCOUNTSTATUS.Pending.ToString(); 

这是为什么好还是最好什么我原本?

编辑

委员会还建议在阵列裹局部变量,主要生产:

string[] acctStatus = {realAccount.AccountStatus.ToString()}; 
if (!SettableStatuses().Any(status => status == acctStatus[0])) 
    acctStatus[0] = ACCOUNTSTATUS.Pending.ToString(); 

这似乎是彻头彻尾的古怪的我。

+0

检查此问题并接受答案,可能有帮助。 http://stackoverflow.com/questions/235455/access-to-modified-closure – Chuck 2009-11-06 15:59:53

回答

34

警告的原因是在循环内部,您可能正在访问正在更改的变量。然而,在这个非循环的上下文中,“修复”并不是真的为你做任何事情。

想象一下,你有一个FOR循环,if是在它内部,并且字符串声明在它之外。在这种情况下,错误会正确地识别抓取不稳定参考的问题。

你不想要的一个例子:

string acctStatus 

foreach(...) 
{ 
    acctStatus = account.AccountStatus[...].ToString(); 
    if (!SettableStatuses().Any(status => status == acctStatus)) 
     acctStatus = ACCOUNTSTATUS.Pending.ToString(); 
} 

的问题是,在关闭将抢acctStatus的引用,但每次循环迭代将会改变该值。在情况下,它会更好:

foreach(...) 
{ 
    string acctStatus = account.AccountStatus[...].ToString(); 
    if (!SettableStatuses().Any(status => status == acctStatus)) 
     acctStatus = ACCOUNTSTATUS.Pending.ToString(); 
} 

由于变量的情况下是循环,一个新的实例将会每次被创建,因为我们已经搬进了当地的环境里面的变量(for循环)。

该建议听起来像是Resharper解析该代码时的一个错误。但是,在很多情况下,这是一个有效的关注点(例如,第一个示例,尽管它在封闭中被捕获,但引用正在改变)。

我的经验法则是,如果有疑问做一个本地。

这是一个现实世界的例子,我被咬伤:

 menu.MenuItems.Clear(); 
     HistoryItem[] crumbs = policyTree.Crumbs.GetCrumbs(nodeType); 

     for (int i = crumbs.Length - 1; i > -1; i--) //Run through items backwards. 
     { 
      HistoryItem crumb = crumbs[i]; 
      NodeType type = nodeType; //Local to capture type. 
      MenuItem menuItem = new MenuItem(crumb.MenuText); 
      menuItem.Click += (s, e) => NavigateToRecord(crumb.ItemGuid, type); 
      menu.MenuItems.Add(menuItem); 
     } 

注意,我抓住的NodeType类型的地方,注意节点类型,并HistoryItem crumb.ItemGuid,不屑[I] .ItemGuid。这可以确保我的关闭不会引用将会更改的项目。

在使用本地化之前,事件会触发当前值,而不是我预期的捕获值。

+0

有很多意义,谢谢! – 2009-11-06 16:06:13

+1

“问题在于闭包将获取对acctStatus的引用,但是每次循环迭代都会更改该值” - 实际上,只要“Any”谓词实际上它总是“account.AccountStatus [...]。ToString()”评估它(因为'Any'在返回之前遍历枚举值),所以我不确定这是一个好例子。我相信你提出的更好的建议会有相同的行为。 – 2010-10-28 22:38:26

+1

这将是不正确的。不同之处在于,在第一个示例中,只分配了一个变量:acctStatus。 Resharper担心在实际评估Any()之前,该变量会发生变化。我的建议并没有改变代码的行为(Any()在任何改变发生之前都被评估过),但是明确地说我们希望对于循环的每次迭代都需要一个变量acctStatus的不同实例。如果你注意我后面的例子,那么Resharper会担心实际触发器,因为我*不会立即评估lambda(减去本地数据)。 – Godeke 2010-10-29 20:39:08

相关问题