【问题标题】:Modifying source items changes list items? [duplicate]修改源项目会更改列表项目? [复制]
【发布时间】:2018-09-18 15:19:58
【问题描述】:

我正在为使用 C# 中的 Windows 窗体的软件编写一个小插件。 我需要解析一个 XML 文件来检索一些对象并将它们添加到 ListBox 中。问题是在我的程序结束时,所有对象都与最后添加的对象相同。 我有点想通为什么,但我仍在寻找如何解决它。这是一个用String[] 代替我的对象的小例子:

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();
}

【问题讨论】:

  • 那是因为你添加了同一个数组引用,所以当你更新数组时,你添加到列表框的引用指向同一个改变的数组。如果你想避免这种情况,你需要创建一个新数组。
  • 感谢大家的建议!我会试一试。 :)

标签: c# winforms listbox


【解决方案1】:

ListBoxes 使用指针,更新第一个数组中的值,您正在更新标记为“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();

【讨论】:

    【解决方案2】:

    使用listbox.Items.Add(s);,您只需添加一项即数组本身。使用AddRange 代替添加数组的元素。

    listbox.Items.AddRange(s);
    

    另一种方法是设置DataSource:

    listbox.DataSource = s;
    

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

    1    String[] s = new string[] { "5", "2", "3" };
    2    listbox.Items.Add(s);
    3    s[2] = "0";
    4    listbox.Items.Add(s);
    
    1. 创建并初始化了一个数组。
    2. 此数组作为单个项目添加到 ListBox。请注意,数组是引用类型。实际上,您只是添加了对 ListBox 的引用,而不是数组的副本。
    3. 数组的一个元素已更改。这也会影响添加到 ListBox 的第一项,因为它包含对这个唯一数组的引用。
    4. 相同的数组引用作为项目添加到 ListBox。现在 ListBox 包含 2 个项目,它们引用了具有相同元素的相同数组。

    如果您希望项目包含 2 个不同的数组,您可以克隆该数组:

    string[] s = new string[] { "5", "2", "3" };
    listbox.Items.Add(s);
    var s2 = (string[])s.Clone();
    s2[2] = "0";
    listbox.Items.Add(s2);
    

    现在您在 ListBox 中有两个不同的项目。请注意,Array.Clone Method 创建了一个浅克隆。 IE。数组元素本身不会被克隆。因此,如果它们是引用类型,则两个数组将在克隆后包含相同的对象。但是由于你有 2 个不同的数组,你可以替换一个数组的元素而不影响另一个数组。

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

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

    MemberwiseClone 继承自 System.Object

    【讨论】:

      【解决方案3】:

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

        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();
         }
      

      【讨论】:

      • 更新了我的答案
      猜你喜欢
      • 1970-01-01
      • 2017-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-11
      相关资源
      最近更新 更多