2013-03-26 145 views
2

我在C#中使用了以下代碼,使用了foreach。在一個循環中,我正在修改List<T>,而在另一個循環中修改了string陣列。在C#中爲迭代變量賦值?

我們不能直接爲迭代變量賦值或空值,但我們可以修改它的屬性,並且修改最終反映在List中。

所以這基本上意味着迭代變量是對列表中元素的引用,那麼爲什麼我們不能直接給它賦值呢?

class Program 
{ 
    public static void Main(string[] args) 
    { 
     List<Student> lstStudents = Student.GetStudents(); 

     foreach (Student st in lstStudents) 
     { 
      // st is modified and the modification shows in the lstStudents 
      st.RollNo = st.RollNo + 1; 

      // not allowed 
      st = null; 
     } 

     string[] names = new string[] { "me", "you", "us" }; 

     foreach (string str in names) 
     { 
      // modifying str is not allowed 
      str = str + "abc"; 
     } 
    } 
} 

學生類:

class Student 
{ 
    public int RollNo { get; set; } 
    public string Name { get; set; } 

    public static List<Student> GetStudents() 
    { 
     List<Student> lstStudents = new List<Student>(); 

     lstStudents.Add(new Student() { RollNo = 1, Name = "Me" }); 
     lstStudents.Add(new Student() { RollNo = 2, Name = "You" }); 
     lstStudents.Add(new Student() { RollNo = 3, Name = "Us" }); 

     return lstStudents; 
    } 
} 
+0

「不允許」是什麼意思? – 2013-03-26 09:03:40

+0

「不允許」表示編譯錯誤。 – Brij 2013-03-26 09:04:34

回答

7

foreach迭代變量是「參考列表中的元素」 - 它僅僅是從.Current {get;}在迭代器實現價值通過GetEnumerator()獲得 - 大多數通常通過IEnumerator[<T>]但並非總是 - 實際上對於List<T>它是一個List<T>.Enumerator價值。在一般情況下,分配給迭代器變量沒有「含義」。試想一下:

IEnumerable<int> RandomSequence(int count) { 
    var rand = new Random(); 
    while(count-->0) yield return rand.Next(); 
} 

這將工作相同foreach - 這一切意味着什麼分配呢?因此,foreach不提供分配給迭代變量的設施。

1

它是一個引用類型,當然如果它們是可寫的,你可以修改它的屬性,這些更改將反映在引用所引用的對象中。

引用類型的變量根據定義是對對象的引用。但是,這與對實際存儲位置(例如變量或列表條目)的引用有所不同。

你可以想像它像一個Student變量只包含尋找原始對象的地址。通過將列表條目複製到變量中,您只需複製地址,現在您有兩個地址,一次在列表中,一次在變量中。通過重新分配變量,您正在編寫另一個地址,但這不會影響列表中的原始條目。它也不會覆蓋之前提到的變量對象。

也就是說,foreach可能不允許您重新分配迭代變量,因爲它可能會導致混淆/錯誤。它目前實現的方式,你總是知道迭代變量是當前元素。

1

這是因爲編譯器通過Enumerator實現了foreach。統計員只能在已關閉的集合中前進,他們不能改變他們迭代的集合。

1

下面是一個具體的例子,應該說清楚。

試想一下,你實現一個IEnumerable<int>像這樣:

public static IEnumerable<int> OneToTen() 
{ 
    for (int i = 1; i <= 10; ++i) 
    { 
     yield return i; 
    } 
} 

鑑於這種情況,這將意味着什麼,如果在下面的循環,你可以分配給n

foreach (var n in OneToTen()) 
{ 
    n = 1; // Change original "collection"? There isn't one! 
} 

編譯器可以讓你改變n無需任何與改變正在迭代的東西,但它會產生誤導 - 這就是爲什麼不允許編譯它。