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文件中的 ...
随机推荐
- 【最优比率生成树】poj2728 Desert King
最优比率生成树教程见http://blog.csdn.net/sdj222555/article/details/7490797 个人觉得很明白易懂,但他写的代码略囧. 模板题,但是必须Prim,不能 ...
- (原创)Stanford Machine Learning (by Andrew NG) --- (week 6) Advice for Applying Machine Learning & Machine Learning System Design
(1) Advice for applying machine learning Deciding what to try next 现在我们已学习了线性回归.逻辑回归.神经网络等机器学习算法,接下来 ...
- PHP5.3魔术方法 __invoke
这个魔幻方法被调用的时机是: 当一个对象当做函数调用的时候, 如果对象定义了__invoke魔幻方法则这个函数会被调用, class Callme { public function __invoke ...
- minGW cygwin gnuwin32
首先,三个的官方网站分别是: minGW:http://www.mingw.org cygwin: http://www.cygwin.com gnuwin32: https://sourcefo ...
- all objects of the same class share the same set of class methods
#include <iostream> #include "First.h" void Test(); int main() { std::cerr<<&q ...
- TStringList的DelimitedText的空格问题
TStringList的DelimitedText的空格问题 如果DelimitedText的字符串中有空格,TStringList遇到空格会进行自动换行,而这显然不是我们想要的结果.经测试发现D7~ ...
- minishift的本地代码构建
看文档说支持,但实际尝试了下,失败 发现仍然是找github中的代码 找了半天,发现是在目录下有.git的隐含目录,然后copy到其他目录下删除,然后再试,发现仍然失败. 日志看是指定的目录并没有传入 ...
- 支持向量机SVM 简要推导过程
SVM 是一块很大的内容,网上有写得非常精彩的博客.这篇博客目的不是详细阐述每一个理论和细节,而在于在不丢失重要推导步骤的条件下从宏观上把握 SVM 的思路. 1. 问题由来 SVM (支持向量机) ...
- ylbtech-LanguageSamples-PythonSample
ylbtech-Microsoft-CSharpSamples:ylbtech-LanguageSamples-PythonSample 1.A,示例(Sample) 返回顶部 本示例演示如何使用 C ...
- 从项目上一个子查询扩展学习开来:mysql的查询、子查询及连接查询
上面这样的数据,想要的结果是:如果matchResult为2的话,代表是黑名单.同一个softId,version,pcInfoId的代表是同一个软件,需要去重:同时,如果相同软件里面只要有一个mat ...