C# 遍历Dictionary并修改其中的Value
C#的Dictionary类型的值,知道key后,value可以修改吗?答案是肯定能修改的。我在遍历的过程中可以修改Value吗?答案是也是肯定能修改的,但是不能用For each循环。否则会报以下的Exception.
System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'
之所以会报Exception是For each本身的问题,和Dictionary没关系。For each循环不能改变集合中各项的值,如果需要迭代并改变集合项中的值,请用For循环。
大家来看下例子:
// defined the Dictionary variable
Dictionary<int, string> td = new Dictionary<int, string>();
td.Add(, "str1");
td.Add(, "str2");
td.Add(, "str3");
td.Add(, "str4");
// test for
TestForDictionary(td);
// test for each
TestForEachDictionary(td);
TestForDictionary Code
static void TestForDictionary(Dictionary<int, string> paramTd)
{ for (int i = ;i<= paramTd.Keys.Count;i++)
{
paramTd[i] = "string" + i;
Console.WriteLine(paramTd[i]);
}
}
TestForDictionary的执行结果
string1
string2
string3
string4
TestForEachDictionary Code
static void TestForEachDictionary(Dictionary<int, string> paramTd)
{
int forEachCnt = ;
foreach (KeyValuePair<int,string> item in paramTd)//System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'
{
paramTd[item.Key] = "forEach" + forEachCnt;
Console.WriteLine(paramTd[item.Key]);
forEachCnt += ;
}
}
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的代码片段贴出来:
[ComVisible(false)]
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(Generic.Mscorlib_DictionaryDebugView<,>))]
[DefaultMember("Item")]
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
{
...
}
Dictionary也有无参公共方法GetEnumerator
//
// 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();
我们再看看Dictionary<TKey, TValue>.Enumerator的代码:
// Summary:
// Enumerates the elements of a System.Collections.Generic.Dictionary<TKey,TValue>.
[Serializable]
public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>, IDisposable, IDictionaryEnumerator, IEnumerator
{ // Summary:
// Gets the element at the current position of the enumerator.
//
// Returns:
// The element in the System.Collections.Generic.Dictionary<TKey,TValue> at
// the current position of the enumerator.
public KeyValuePair<TKey, TValue> Current { get; } // Summary:
// Releases all resources used by the System.Collections.Generic.Dictionary<TKey,TValue>.Enumerator.
public void Dispose();
//
// Summary:
// Advances the enumerator to the next element of the System.Collections.Generic.Dictionary<TKey,TValue>.
//
// Returns:
// true if the enumerator was successfully advanced to the next element; false
// if the enumerator has passed the end of the collection.
//
// Exceptions:
// System.InvalidOperationException:
// The collection was modified after the enumerator was created.
public bool MoveNext();
}
让我们看看,我们能否修改KeyValuePair的值
public struct KeyValuePair<TKey, TValue>
{
//
// Summary:
// Initializes a new instance of the System.Collections.Generic.KeyValuePair<TKey,TValue>
// structure with the specified key and value.
//
// Parameters:
// key:
// The object defined in each key/value pair.
//
// value:
// The definition associated with key.
public KeyValuePair(TKey key, TValue value); // Summary:
// Gets the key in the key/value pair.
//
// Returns:
// A TKey that is the key of the System.Collections.Generic.KeyValuePair<TKey,TValue>.
public TKey Key { get; }
//
// Summary:
// Gets the value in the key/value pair.
//
// Returns:
// A TValue that is the value of the System.Collections.Generic.KeyValuePair<TKey,TValue>.
public TValue Value { get; } // Summary:
// Returns a string representation of the System.Collections.Generic.KeyValuePair<TKey,TValue>,
// using the string representations of the key and value.
//
// Returns:
// A string representation of the System.Collections.Generic.KeyValuePair<TKey,TValue>,
// which includes the string representations of the key and value.
public override string ToString();
}
大家看到了,TValue Value { get; }是我们需要修改的项,只有get方法,所以它是只读的。
上面是从代码方面解释foreach迭代时不可改变集合项,还有一个原因是是你改变值类型的值时,它对应的栈地址也就相应的改变了,这个大家都知道,我就不多说了。那么问题来了,如果我不改变变量的地址,是不是我就可以用Foreach改变集合项呢?答案是肯定的。可以看下边MSDN的代码:
static void ModifyDictionaryValueForEach()
{
Span<int> storage = stackalloc int[];
int num = ;
foreach (ref int item in storage)
{
item = num++;
} foreach (ref readonly var item in storage)
{
Console.Write($"{item} ");
}
// Output:
// 0 1 2 3 4 5 6 7 8 9
}
上边的代码必须是在C#版本是7.3下运行.Span<T>是.net Core2.1里的类型。然后使用ref就可以改变了。大家可以试试。
// // 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();
C# 遍历Dictionary并修改其中的Value的更多相关文章
- [译]聊聊C#中的泛型的使用(新手勿入) Seaching TreeVIew WPF 可编辑树Ztree的使用(包括对后台数据库的增删改查) 字段和属性的区别 C# 遍历Dictionary并修改其中的Value 学习笔记——异步 程序员常说的「哈希表」是个什么鬼?
[译]聊聊C#中的泛型的使用(新手勿入) 写在前面 今天忙里偷闲在浏览外文的时候看到一篇讲C#中泛型的使用的文章,因此加上本人的理解以及四级没过的英语水平斗胆给大伙进行了翻译,当然在翻译的过程中发 ...
- C#遍历Dictionary
C#遍历Dictionary方法 Dictionary<string, int> d = new Dictionary<string, int>(); foreach (Key ...
- [AS3] 问个很囧的问题: 如何遍历Dictionary?
可以使用 for...in 循环或 for each...in 循环来遍历 Dictionary 对象的内容. for...in 循环用于基于键进行遍历: 而 for each...in 循环用于 ...
- .NET(C#)如何遍历Dictionary
我们知道.NET中的Dictionary是键/值对的集合,使用起来也是比较方便,Dictionary也可以用KeyValuePair来迭代遍历,具体如下: using System; using Sy ...
- Java循环遍历中直接修改遍历对象
Java 循环遍历中直接修改遍历对象如下,会报异常: for (ShopBaseInfo sp: sourceList) { if(sp.getId()==5){ sourceList.remove( ...
- Java遍历HashMap并修改(remove)(转载)
遍历HashMap的方法有多种,比如通过获取map的keySet, entrySet, iterator之后,都可以实现遍历,然而如果在遍历过程中对map进行读取之外的操作则需要注意使用的遍历方式和操 ...
- Java遍历HashMap并修改(remove)
遍历HashMap的方法有多种,比如通过获取map的keySet, entrySet, iterator之后,都可以实现遍历,然而如果在遍历过程中对map进行读取之外的操作则需要注意使用的遍历方式和操 ...
- 遍历 Dictionary,你会几种方式?
一:背景 1. 讲故事 昨天在 StackOverflow 上看到一个很有趣的问题,说: 你会几种遍历字典的方式,然后跟帖就是各种奇葩的回答,挺有意思,马上就要国庆了,娱乐娱乐吧,说说这种挺无聊的问题 ...
- Java之递归遍历目录,修改指定文件的指定内容
EditProperties.java package PropertiesOperation.Edit; import java.io.File; /** * 替换指定Porpoerties文件中的 ...
随机推荐
- 【强连通分量缩点】【拓扑排序】【dp预处理】CDOJ1640 花自飘零水自流,一种相思,两处闲愁。
题意: 在n个点m条边的有向图上,从1出发的回路最多经过多少个不同的点 可以在一条边上逆行一次 题解: 在同一个强连通分量中,显然可以经过当中的每一个点 因此先将强连通分量缩点,点权为强连通分量的点数 ...
- [USACO13NOV]No Change
题目大意: 你有k(k<=16)个硬币,每个硬币都有自己的面值. 现在你要给n件商品付钱,每件商品也有自己的价格. 然而老板是个奸商,他绝对不会给你找钱. 你每次付钱只能用一个硬币,但是你可以一 ...
- Codeforces Gym 100269G Garage 数学
Garage 题目连接: http://codeforces.com/gym/100269/attachments Description Wow! What a lucky day! Your co ...
- PHP 自定义字符串中的变量名解析
PHP 自定义字符串中的变量名解析 这样一个需求:页面的 title 可以在后台自定义,自定义内容中可能包含变量,变量用 {$var} 表示, 其中 $var 为变量名 将 title 字段存入数 ...
- iOS 常用工具库LFKit功能介绍
简介:LFKit包含了平时常用的category,封装的常用组件,一些工具类. 需要LFKit中所有自定义控件的pod 'LFKit/Component' 需要LFKit中所有category的pod ...
- GCC,LLVM,Clang编译器对比
http://www.cnblogs.com/qoakzmxncb/archive/2013/04/18/3029105.html 在XCode中,我们经常会看到这些编译选项(如下图),有些人可能 ...
- andriod inputbox
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...
- JavaScript基础入门教程(六)
说明 在看这篇博文之前还是希望读者阅读本系列前几篇文章,还有就是该系列需要读者拥有其它语言的编程基础,一些基本的知识点,比如什么是形参和实参将不再赘述.这篇博文主要讲函数. 函数的定义 在js种支持函 ...
- socket连接和http连接的区别
socket连接和http连接的区别 HTTP协议:简单对象访问协议,对应于应用层 ,HTTP协议是基于TCP连接的 tcp协议: 对应于传输层 ip协议: 对应于网络层 TCP/IP ...
- [转]SSIS - Connect to Oracle on a 64-bit machine (Updated for SSIS 2008 R2)
本文转自:http://sqlblog.com/blogs/jorg_klein/archive/2011/06/09/ssis-connect-to-oracle-on-a-64-bit-machi ...