是否有任何理由将参数值分配给方法中的局部变量,以便使用值而不更改?即如下:
private void MyMethod(string path)
{
string myPath = path;
StreamReader mystream = new StreamReader(myPath);
...
}
或者我可以像这样(并且上面的代码是多余的而且不干净):
private void MyMethod(string path)
{
StreamReader mystream = new StreamReader(path);
...
}
我知道它有两种方式,但我想确保在我的理解中没有遗漏任何东西。
答案 0 :(得分:4)
您需要执行此操作(本地分配)的唯一情况是您是在foreach循环中还是使用Linq。否则,您可能会遇到修改后的闭包问题。
以下是MSDN博客的摘录(以下所有内容均来自链接)。
但我领先于自己。这个片段的输出是什么?
var values = new List<int>() { 100, 110, 120 };
var funcs = new List<Func<int>>();
foreach(var v in values)
funcs.Add( ()=>v );
foreach(var f in funcs)
Console.WriteLine(f());
大多数人都认为它是100/110/120。实际上是120/120/120。为什么?
因为()=&gt; v表示“返回变量v的当前值”,而不是“在创建委托时返回值v返回”。闭包关闭变量,而不是值。当方法运行时,显然分配给v的最后一个值是120,所以它仍然具有该值。
这非常令人困惑。编写代码的正确方法是:
foreach(var v in values)
{
var v2 = v;
funcs.Add( ()=>v2 );
}
现在会发生什么?每次我们重新启动循环体时,我们逻辑上都会创建一个新的变量v2。每个闭包都在不同的v2上关闭,该v2仅分配给一次,因此它始终保持正确的值。
基本上,问题出现是因为我们指定foreach循环是
的语法糖 {
IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator();
try
{
int m; // OUTSIDE THE ACTUAL LOOP
while(e.MoveNext())
{
m = (int)(int)e.Current;
funcs.Add(()=>m);
}
}
finally
{
if (e != null) ((IDisposable)e).Dispose();
}
}
如果我们指定扩展
try
{
while(e.MoveNext())
{
int m; // INSIDE
m = (int)(int)e.Current;
funcs.Add(()=>m);
}
然后代码将按预期运行。
答案 1 :(得分:3)
这是完全相同的,唯一的区别是在第一种情况下你制作了一个引用的副本(当方法超出范围时会被销毁,这在执行结束时会发生)。
为了更好的可读性,请坚持使用第二种情况。
答案 2 :(得分:1)
我更喜欢第二种选择。用参数创建一个新变量是没有意义的。此外,从阅读的角度来看,从路径(您收到的路径)创建流而不是实例化“myPath”变量更有意义。