首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在C#中,为什么我不能在foreach循环中修改值类型实例的成员?

在C#中,为什么我不能在foreach循环中修改值类型实例的成员?
EN

Stack Overflow用户
提问于 2011-04-13 22:15:18
回答 8查看 42.1K关注 0票数 78

我知道值类型应该是不可变的,但这只是一个建议,而不是规则,对吧?那么为什么我不能这样做呢:

代码语言:javascript
复制
struct MyStruct
{
    public string Name { get; set; }
}

 public class Program
{
    static void Main(string[] args)
    {
        MyStruct[] array = new MyStruct[] { new MyStruct { Name = "1" }, new MyStruct { Name = "2" } };
        foreach (var item in array)
        {
            item.Name = "3";
        }
        //for (int i = 0; i < array.Length; i++)
        //{
        //    array[i].Name = "3";
        //}

        Console.ReadLine();
    }
}

代码中的foreach循环无法编译,而带注释的for循环运行良好。错误消息:

无法修改“item”的成员,因为它是“foreach迭代变量”

为什么会这样呢?

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2011-04-13 22:27:23

因为foreach使用枚举器,并且枚举器不能更改基础集合,但是可以更改集合中的对象引用的任何对象。这就是值和引用类型语义发挥作用的地方。

在引用类型(即类)上,所有集合存储的都是对对象的引用。因此,它实际上从来没有接触过对象的任何成员,并且根本不关心它们。对对象的更改不会影响集合。

另一方面,值类型将其整个结构存储在集合中。如果不更改集合并使枚举数无效,则无法访问其成员。

此外,枚举数返回集合中的值的副本。在ref类型中,这没有任何意义。引用的副本将是相同的引用,您可以以任何想要的方式更改被引用的对象,并将更改扩展到范围之外。另一方面,值类型意味着您得到的只是对象的一个副本,因此对该副本的任何更改都不会传播。

票数 83
EN

Stack Overflow用户

发布于 2011-04-13 22:20:06

这是一个建议,从这个意义上说,没有什么能阻止你违反它,但它确实应该比“这是一个建议”更重要。例如,由于您在这里看到的原因。

值类型将实际值存储在变量中,而不是引用中。这意味着您的数组中有值,并且在item中有该值的副本,而不是引用。如果允许更改item中的值,则不会反映在数组中的值上,因为它是一个全新的值。这就是为什么它是不被允许的。

如果你想这样做,你必须按索引循环数组,而不是使用临时变量。

票数 19
EN

Stack Overflow用户

发布于 2011-04-13 22:46:25

结构是值类型。

类是引用类型。

ForEach构造使用IEnumerator of IEnumerable数据类型元素。当发生这种情况时,变量在某种意义上是只读的,您不能修改它们,并且由于您具有值类型,因此您不能修改所包含的任何值,因为它共享相同的内存。

C#语言规范第8.8.4节:

迭代变量对应于一个只读局部变量,其作用域扩展到嵌入式语句

要修复此问题,请使用结构的类实例;

代码语言:javascript
复制
class MyStruct {
    public string Name { get; set; }
}

编辑:@CuiPengFei

如果你使用var隐式类型,编译器很难帮到你。如果你使用MyStruct,它会告诉你结构的情况,它是只读的。在类的情况下,对该项的引用是只读的,因此您不能在循环中编写item = null;,但您可以更改它的属性,这些属性是可变的。

您还可以使用(如果您喜欢使用struct):

代码语言:javascript
复制
        MyStruct[] array = new MyStruct[] { new MyStruct { Name = "1" }, new MyStruct { Name = "2" } };
        for (int index=0; index < array.Length; index++)
        {
            var item = array[index];
            item.Name = "3";
        }
票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5650705

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档