根据下面的代码,我很想知道如何避免以下异常
System.InvalidOperationException was unhandled
Message=Collection was modified; enumeration operation may not execute.
Source=mscorlib
StackTrace:
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at System.Collections.Generic.List`1.Enumerator.MoveNext()
at PBV.Program.Main(String[] args) in C:\Documents and Settings\tmohojft\Local Settings\Application Data\Temporary Projects\PBV\Program.cs:line 39
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException: 代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PBV
{
class Program
{
struct structItem
{
public int y { get; set; }
public int z { get; set; }
}
struct testStruct
{
public int x { get; set; }
public List<structItem> items { get; set; }
}
static void Main(string[] args)
{
testStruct a = new testStruct();
structItem b = new structItem();
for (byte i = 0; i <= 10; i++) {
b.y = i;
b.z = i * 2;
a.items = new List<structItem>();
a.items.Add(b);
}
testStruct c = new testStruct();
c = a;
int counter = 0;
//exception thrown on line below
foreach (var item in a.items) {
structItem d = item;
d.z = 3;
c.items[counter] = d;
counter++;
}
a = c;
}
}
}我最初试图在第二篇文章中简单地说明以下几点:
item.z = 3;但是,这导致了以下错误:
Cannot modify members of "item" because it is a "foreach iteration" 我试图创建一个临时对象,以便能够修改foreach中的struct数据,但我收到了上面的异常。我最好的猜测是,我的临时结构保存了对原始结构的引用,而不是值本身--这将导致我的原始结构在临时结构被更新时被更新。
因此,我的问题是:如何通过值而不是引用传递这个结构?或者有一种完全不同的方法来解决这个问题?
提前谢谢你的帮助。
编辑:谢谢所有的答案,伙计们。我知道列表是一种引用类型,但这是否使得不可能通过值而不是引用传递呢?
发布于 2012-05-18 18:10:41
我对您的示例代码试图做什么感到有点困惑,但我认为您的部分困惑可能是,当您设置c = a时,您希望它生成列表的副本。事实并非如此。虽然结构本身是值类型,但它包含的项属性不是。List<>是一个引用类型,所以当您设置c = a时,它会将items引用复制到c。因此,当您进入循环时,a和c都包含对同一个list对象的引用。因此,当您在枚举列表时修改它时,它总是失败的。
避免这种情况的一个简单方法是迭代列表的静态副本:
foreach (var item in a.items.ToArray())发布于 2012-05-18 18:26:32
a.Items和c.Items仍然是完全相同的List实例。您可以使用一个老式的for循环来迭代它。这样,您就不会使用任何枚举数,因此可以随意修改列表。
for (int i = 0; i < a.Items.Count; i++)
{
c.Items[i] = whatever;
}无论如何,你都要保留一个柜台,所以这似乎是一种自然的方法。出于性能考虑,如果不打算添加或删除任何项,则可能希望将列表大小存储在局部变量中。
发布于 2012-05-18 18:28:11
可变值对象(struct)比不可变对象更难处理。考虑使结构不可变,并围绕它重新设计代码。
不使用struct通常更容易,除非您知道具体的好处和痛点在哪里。尝试将您的代码改为类,并衡量性能是否符合您的目标。
注意:c = a;是浅层复制(实际上并不是对testStruct进行第二次复制,而是指a),它似乎需要深度复制--考虑将其改为构造函数,并复制数组而不是引用它。
https://stackoverflow.com/questions/10657657
复制相似问题