C# 是否修改源项更改列表项?

C# 是否修改源项更改列表项?,c#,winforms,listbox,C#,Winforms,Listbox,我正在为一个使用C#中Windows窗体的软件编写一个小插件。 我需要解析一个XML文件来检索一些对象,并将它们添加到列表框中。问题是,在我的程序结束时,所有对象都与最后添加的对象相同。 我知道了原因,但我仍在寻找解决方法。下面是一个使用字符串[]代替我的对象的小示例: static void Main(string[] args) { ListBox listbox = new ListBox(); String[] s = new string[] { "5", "2", "

我正在为一个使用C#中Windows窗体的软件编写一个小插件。 我需要解析一个XML文件来检索一些对象,并将它们添加到
列表框中。问题是,在我的程序结束时,所有对象都与最后添加的对象相同。
我知道了原因,但我仍在寻找解决方法。下面是一个使用
字符串[]
代替我的对象的小示例:

static void Main(string[] args)
{
    ListBox listbox = new ListBox();
    String[] s = new string[] { "5", "2", "3" };
    listbox.Items.Add(s);
    s[2] = "0";
    listbox.Items.Add(s);

    Console.WriteLine(((String[])listbox.Items[0])[2]); // result => 0
    Console.WriteLine(((String[])listbox.Items[1])[2]); // result => 0
    Console.ReadLine();
}

它显示最后更新的值,因为字符串是引用类型,将在更新时替换所有现有引用。因此,您需要创建新数组,然后将其作为源添加到列表框中

  static void Main(string[] args)
   {
    ListBox listbox = new ListBox();
    String[] s = new string[] { "5", "2", "3" };
    listbox.Items.Add(s);
    String[] s2 = new string[] { "5", "2", "0" };
    listbox.Items.Add(s2);

    Console.WriteLine(((String[])listbox.Items[0])[2]); // result => 0
    Console.WriteLine(((String[])listbox.Items[1])[2]); // result => 0
    Console.ReadLine();
   }

使用
listbox.Items.Add您只添加了一项,即数组本身。使用
AddRange
来添加数组的元素

listbox.Items.AddRange(s);
另一种方法是设置:


让我们详细看看代码中发生了什么(行号)

  • 创建并初始化一个数组
  • 此数组作为一个项目添加到列表框中。请注意,数组是引用类型。因此,实际上,您只是添加了对列表框的引用,而不是数组的副本
  • 数组的一个元素已更改。这也会影响添加到列表框的第一个项目,因为它包含对此唯一数组的引用
  • 将相同的数组引用作为一项添加到列表框中。现在,ListBox包含两个项目,它们引用具有相同元素的相同数组
  • 如果希望项目包含两个不同的数组,可以克隆该数组:

    string[] s = new string[] { "5", "2", "3" };
    listbox.Items.Add(s);
    var s2 = (string[])s.Clone();
    s2[2] = "0";
    listbox.Items.Add(s2);
    
    现在列表框中有两个不同的项。请注意,将创建一个浅克隆。也就是说,数组元素本身不是克隆的。因此,如果它们是引用类型,则两个数组在克隆后将包含相同的对象。但由于您有两个不同的数组,因此可以替换一个数组的元素而不影响另一个数组

    您可以将克隆方法添加到自己的类中

    public class MyOwnClass
    {
        public string Prop1 { get; set; }
        public int Prop2 { get; set; }
    
        public MyOwnClass ShallowClone()
        {
            return (MyOwnClass)MemberwiseClone();
        }
    }
    

    MemberwiseClone
    继承自
    系统。对象

    列表框使用指针,更新第一个数组中的值,更新标记为“s”的指针的值,为了使用相同的值名但不同的数组,必须克隆起始数组

    ListBox listbox = new ListBox();
    String[] s = new string[] { "5", "2", "3" };
    listbox.Items.Add(s);
    s = (String[])s.Clone();
    s[2] = "0";
    listbox.Items.Add(s);
    Console.WriteLine(((String[])listbox.Items[0])[2]); // result => 3
    Console.WriteLine(((String[])listbox.Items[1])[2]); // result => 0
    Console.ReadLine();
    

    这是因为添加了相同的数组引用,所以在更新数组时,添加到列表框中的引用指向相同的已更改数组。如果你想避免这种情况,你需要创建一个新的数组。谢谢大家的建议!我要试一试。:)更新了我的答案
    public class MyOwnClass
    {
        public string Prop1 { get; set; }
        public int Prop2 { get; set; }
    
        public MyOwnClass ShallowClone()
        {
            return (MyOwnClass)MemberwiseClone();
        }
    }
    
    ListBox listbox = new ListBox();
    String[] s = new string[] { "5", "2", "3" };
    listbox.Items.Add(s);
    s = (String[])s.Clone();
    s[2] = "0";
    listbox.Items.Add(s);
    Console.WriteLine(((String[])listbox.Items[0])[2]); // result => 3
    Console.WriteLine(((String[])listbox.Items[1])[2]); // result => 0
    Console.ReadLine();