我需要一个通过值和可变传递的对象

时间:2013-06-28 06:18:06

标签: c# list class struct mutable

我是C#的新手,所以请耐心等待。我在c#中遇到问题,我无法决定是否需要类或结构。我正在创建一个类或结构的List,并向其添加元素。如果我使用结构,那么我可以添加一个项目,更改它,然后重新添加它,并且会看到更改,因为它是按值传递的。问题是,结构不可变,所以我以后不能编辑任何元素。如果我使用一个类,那么如果我添加一个项并对其进行更改,则列表中的所有项都会更改。如果我希望它不同,我每次都要创建一个新的对象实例。但我有一个对象,我只想更改一个项目,所以我必须将所有其他项目复制到新对象?!为什么?有更好的解决方案吗?

此代码说明了我的问题:

namespace TestError
{
    public partial class Form1 : Form
    {
        private List<Thing> lst;
        private Thing obj;

        public Form1()
        {
            InitializeComponent();

            lst = new List<Thing>();
            obj = new Thing();

            obj.a = "bla";
            lst.Add(obj);
            //obj = new Thing();
            obj.a = "thing";
            lst.Add(obj);

            foreach (Thing t in lst)
                listBox1.Items.Add(t.a);
        }
    }

    class Thing
    {
        public string a;
        //problem is there are many more items here that don't change!
    }
}

为什么结构不起作用:

namespace TestError
{
    public partial class Form1 : Form
    {
        private List<Thing> lst;
        private Thing obj;

        public Form1()
        {
            InitializeComponent();

            lst = new List<Thing>();
            obj = new Thing();

            obj.a = "bla";
            lst.Add(obj);
            lst[0].a = "new";  //error. if i change it to class, it works.
            obj.a = "thing";
            lst.Add(obj);

            foreach (Thing t in lst)
                listBox1.Items.Add(t.a);
        }
    }

    struct Thing
    {
        public string a;
    }
}

2 个答案:

答案 0 :(得分:0)

课程是要走的路。自从我离开大学以来,我从未触及结构类型。

对于Thing课程,您说“这里有更多项目不会改变!”。这是指值是固定的还是值基于初始对象。如果值已修复,则可以在类中指定一些默认值。

如果值基于初始对象,我看不到在将对象添加到列表时传递变量的麻烦。

答案 1 :(得分:0)

  

问题是,结构不可变,所以我以后不能编辑任何元素。

这根本不是真的;不要误会我的意思,我认为这是一个 非常糟糕的主意 来做你想做的事情,我认为class带有{ {1}}方法将是最佳解决方案,但您正在考虑这个问题的原因恰恰是由于值类型语义。您需要记住,列表索引器(Clone())是方法 - 和 直接访问;考虑:

[0]

如果编译,这行将会是:

  • 从列表中取出对象的副本(现在这是一个完全隔离且单独的副本)
  • 更改副本上的字段
  • 弃用副本

编译器知道这肯定不是你想要的,所以它可以防止你犯错;那里的用法是:

lst[0].a = "new";

奇怪的是,如果var tmp = lst[0]; tmp.a = "new"; lst[0].a = tmp; 数组,那么工作 - 数组允许直接原位编辑:

lst

会编译。 但是,请不要这样做

  • 可变结构是一个坏主意,而导致代码中出现大量混淆
  • 公共字段也是一个坏主意
  • 大型结构也是一个坏主意

就像我说的,我在这里的建议是lst[0].a = "new"; ;如果您想要方便的复制语义,那么 添加class方法