倒車

2011-09-16 49 views
1

我已經在使用該功能倒車

static IEnumerable<Func<int>> MakeEnumerator(int[] values) 
    { 
     for (int a = 0; a < values.Length; a++) 
     { 
      yield return() => Values[a]; 
     } 
    } 

我不能再反向此使用LINQ或轉換爲數組沒有所有的值成爲最後一個函數創建的ienumarable lambda函數lambda函數的ienumarable。 示例代碼(注意,這只是說明了問題它不是在應用程序代碼):

 int[] start = {1,2,3}; 

     IEnumerable<Func<int>> end = MakeEnumerator(start).Reverse<Func<int>>(); 

     foreach (Func<int> i in end) 
     { 
      Console.WriteLine(i()); 
     } 

我認爲這個問題是在MakeEnumerator功能。我將如何修改它以使其工作或編寫可用的替換反向函數。

+0

像Resharper這樣的代碼檢測工具會在這種情況下顯示一個警告,並且通常會提出一個建議的解決方案。 –

回答

5

問題是你正在捕獲循環變量。所有代表都捕獲相同的變量,因此他們將始終在您的用例中看到a的最新值......在您執行代表時,它將爲values.Length + 1。你可以簡單地複製它,而不是:

for (int a = 0; a < values.Length; a++) 
{ 
    int copy = a; 
    yield return() => Values[copy]; 
} 

或者(和preferrably IMO)使用foreach循環,目前需要相同的解決方法:

foreach (int value in values) 
{ 
    int copy = value; 
    yield return() => copy; 
} 

或者更好的是:

return values.Select(x => (Func<int>)(() => x)); 

或者:

Func<int, Func<int>> projection = x =>() => x; 
return values.Select(projection); 

查看Eric Lippert的博客文章"Closing over the loop variable considered harmful"瞭解更多信息。請注意,對於C#4.5,foreach的行爲可能會發生變化。

+0

關於'foreach'的計劃更改,有沒有什麼可靠的東西(也就是某處寫的東西)? – BrokenGlass

+0

@BrokenGlass:Eric Lippert在Stack Overflow的評論中做出了合理的預測,即它將會改變。儘管我在博客文章中沒有看到任何明確的內容。 –

+0

你爲什麼不簡單寫'yield return()=> value;'? – Nawaz

2

所有的lambda表達式都是sharing the same a variable
由於您只在循環結束後調用它們,因此a始終爲3

你需要給每一個自己的變量:

for (int dontUse = 0; dontUse < values.Length; dontUse++) 
{ 
    int a = dontUse; 
    yield return() => Values[a]; 
} 

在此代碼,每個lambda表達式都有自己的a變量(因爲它的內循環範圍的),而這些不同的變量永遠不會改變。