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文件中的 ...
随机推荐
- python debug open_files
主要是遇到 Error 24, too many open files. 下面这种方法可以debug打开了哪些文件. import __builtin__ openfiles = set() oldf ...
- Codeforces Beta Round #3 B. Lorry 暴力 二分
B. Lorry 题目连接: http://www.codeforces.com/contest/3/problem/B Description A group of tourists is goin ...
- hibernate使用原生SQL查询
以下是Demo测试Hibernate 原生SQL查询: import java.util.Iterator; import java.util.List; import java.util.Map; ...
- 移动端调试神器(eruda)
在日常的移动端开发时,一般都是试用chrome浏览器的移动端模式进行开发和调试,只有在chrome调试完成,没有问题了才会上到真机测试,移动端开发的一大问题就在于此, 各种品牌各种型号手机,手机中各种 ...
- express.Router创建模块化路由
使用 app.route() 创建路由路径的链式路由句柄.由于路径在一个地方指定,这样做有助于创建模块化的路由,而且减少了代码冗余和拼写错误. 先放小实例: app.js var express = ...
- jQuery Ajax 参数解析
简单的例子: $.ajax({ type:"post", data:{a:acon,b:bcon} , url:"ajax.php", async:false ...
- [Linux] Proc 文件系统
转载自:http://linux.chinaunix.net/doc/2004-10-05/16.shtml#324lfindex0 目录: /proc --- 一个虚拟文件系统 加载 proc 文件 ...
- SQLAlchemy中filter()和filter_by()的区别
1.filter引用列名时,使用“类名.属性名”的方式,比较使用两个等号“==” 2.filter_by引用列名时,使用“属性名”,比较使用一个等号“=” 3.在使用多条件匹配的时候,filter需要 ...
- [转]sqlserver2008锁表语句详解
本文转自:http://xue.uplook.cn/database/sqlserver/801760.html 锁定数据库的一个表 代码如下: SELECT * FROM table WITH (H ...
- 高性能WEB开发:Javascript自身执行效率
Javascript中的作用域链.闭包.原型继承.eval等特性,在提供各种神奇功能的同时也带来了各种效率问题,用之不慎就会导致执行效率低下. 1.全局导入 我们在编码过程中多多少少会使用到一些全局变 ...