C# 遍歷Dictionary並修改其中的Value

C#的Dictionary類型的值,知道key後,value能夠修改嗎?答案是確定能修改的。我在遍歷的過程當中能夠修改Value嗎?答案是也是確定能修改的,可是不能用For each循環。不然會報如下的Exception.ide

System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'

之因此會報Exception是For each自己的問題,和Dictionary不要緊。For each循環不能改變集合中各項的值,若是須要迭代並改變集合項中的值,請用For循環。spa

你們來看下例子:.net

 1             // defined the Dictionary variable
 2             Dictionary<int, string> td = new Dictionary<int, string>();
 3             td.Add(1, "str1");
 4             td.Add(2, "str2");
 5             td.Add(3, "str3");
 6             td.Add(4, "str4");
 7             // test for
 8             TestForDictionary(td);
 9             // test for each
10             TestForEachDictionary(td);
TestForDictionary Code
1         static void TestForDictionary(Dictionary<int, string> paramTd)
2         {
3             
4             for (int i = 1;i<= paramTd.Keys.Count;i++)
5             {
6                 paramTd[i] = "string" + i;
7                 Console.WriteLine(paramTd[i]);
8             }
9         }
TestForDictionary的執行結果
string1
string2
string3
string4
 
TestForEachDictionary Code
 1         static void TestForEachDictionary(Dictionary<int, string> paramTd)
 2         {
 3             int forEachCnt = 1;
 4             foreach (KeyValuePair<int,string> item in paramTd)//System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'
 5             {
 6                 paramTd[item.Key] = "forEach" + forEachCnt;
 7                 Console.WriteLine(paramTd[item.Key]);
 8                 forEachCnt += 1;
 9             }
10         }
TestForEachDictionary裏的For each會在循環第二次的時候報錯,也就是說它會在窗口中打印出「forEach1」後斷掉。
---------------------------------------------------------------------------------------------------------------------------------------------------
爲何foreach循環不能改變Dictionary中Key對應的Value?
 首先,咱們知道要使用Foreach in語句須要知足下列條件:
1.迭代集合實現了System.Collections.IEnumerable或者System.Collections.Generic.IEnumerable<T>接口;
2.有public Enumerator GetEnumerator();方法
3.GetEnumerator的返回類型是Enumerator,那就必須有Current屬性和MoveNext方法
其實1,2,3是一個東西,關聯性很強。
我迭代的集合是Dictionary,我把Dictionary的代碼片斷貼出來:
1     [ComVisible(false)]
2     [DebuggerDisplay("Count = {Count}")]
3     [DebuggerTypeProxy(typeof(Generic.Mscorlib_DictionaryDebugView<,>))]
4     [DefaultMember("Item")]
5     public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IEnumerable, IDictionary, ICollection, IReadOnlyDictionary<TKey, TValue>, IReadOnlyCollection<KeyValuePair<TKey, TValue>>, ISerializable, IDeserializationCallback
6     {
7     ...
8     }

Dictionary也有無參公共方法GetEnumeratorcode

1 //
2         // Summary:
3         //     Returns an enumerator that iterates through the System.Collections.Generic.Dictionary<TKey,TValue>.
4         //
5         // Returns:
6         //     A System.Collections.Generic.Dictionary<TKey,TValue>.Enumerator structure
7         //     for the System.Collections.Generic.Dictionary<TKey,TValue>.
8         public Dictionary<TKey, TValue>.Enumerator GetEnumerator();

咱們再看看Dictionary<TKey, TValue>.Enumerator的代碼blog

 1         // Summary:
 2         //     Enumerates the elements of a System.Collections.Generic.Dictionary<TKey,TValue>.
 3         [Serializable]
 4         public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>, IDisposable, IDictionaryEnumerator, IEnumerator
 5         {
 6 
 7             // Summary:
 8             //     Gets the element at the current position of the enumerator.
 9             //
10             // Returns:
11             //     The element in the System.Collections.Generic.Dictionary<TKey,TValue> at
12             //     the current position of the enumerator.
13             public KeyValuePair<TKey, TValue> Current { get; }
14 
15             // Summary:
16             //     Releases all resources used by the System.Collections.Generic.Dictionary<TKey,TValue>.Enumerator.
17             public void Dispose();
18             //
19             // Summary:
20             //     Advances the enumerator to the next element of the System.Collections.Generic.Dictionary<TKey,TValue>.
21             //
22             // Returns:
23             //     true if the enumerator was successfully advanced to the next element; false
24             //     if the enumerator has passed the end of the collection.
25             //
26             // Exceptions:
27             //   System.InvalidOperationException:
28             //     The collection was modified after the enumerator was created.
29             public bool MoveNext();
30         }

讓咱們看看,咱們可否修改KeyValuePair的值接口

 1     public struct KeyValuePair<TKey, TValue>
 2     {
 3         //
 4         // Summary:
 5         //     Initializes a new instance of the System.Collections.Generic.KeyValuePair<TKey,TValue>
 6         //     structure with the specified key and value.
 7         //
 8         // Parameters:
 9         //   key:
10         //     The object defined in each key/value pair.
11         //
12         //   value:
13         //     The definition associated with key.
14         public KeyValuePair(TKey key, TValue value);
15 
16         // Summary:
17         //     Gets the key in the key/value pair.
18         //
19         // Returns:
20         //     A TKey that is the key of the System.Collections.Generic.KeyValuePair<TKey,TValue>.
21         public TKey Key { get; }
22         //
23         // Summary:
24         //     Gets the value in the key/value pair.
25         //
26         // Returns:
27         //     A TValue that is the value of the System.Collections.Generic.KeyValuePair<TKey,TValue>.
28         public TValue Value { get; }
29 
30         // Summary:
31         //     Returns a string representation of the System.Collections.Generic.KeyValuePair<TKey,TValue>,
32         //     using the string representations of the key and value.
33         //
34         // Returns:
35         //     A string representation of the System.Collections.Generic.KeyValuePair<TKey,TValue>,
36         //     which includes the string representations of the key and value.
37         public override string ToString();
38     }

你們看到了,TValue Value { get; }是咱們須要修改的項,只有get方法,因此它是隻讀的。ci


上面是從代碼方面解釋foreach迭代時不可改變集合項,還有一個緣由是是你改變值類型的值時,它對應的棧地址也就相應的改變了,這個你們都知道,我就很少說了。那麼問題來了,若是我不改變變量的地址,是否是我就能夠用Foreach改變集合項呢?答案是確定的。能夠看下邊MSDN的代碼:element

 1 static void ModifyDictionaryValueForEach()
 2  {
 3      Span<int> storage = stackalloc int[10];
 4      int num = 0;
 5      foreach (ref int item in storage)
 6      {
 7          item = num++;
 8      }
 9  
10      foreach (ref readonly var item in storage)
11      {
12          Console.Write($"{item} ");
13      }
14      // Output:
15      // 0 1 2 3 4 5 6 7 8 9
16  }

上邊的代碼必須是在C#版本是7.3下運行.Span<T>是.net Core2.1裏的類型。而後使用ref就能夠改變了。你們能夠試試。get

 

 

//        // Summary:        //     Returns an enumerator that iterates through the System.Collections.Generic.Dictionary<TKey,TValue>.        //        // Returns:        //     A System.Collections.Generic.Dictionary<TKey,TValue>.Enumerator structure        //     for the System.Collections.Generic.Dictionary<TKey,TValue>.        public Dictionary<TKey, TValue>.Enumerator GetEnumerator();string

相關文章
相關標籤/搜索