【问题标题】:Swapping Objects in an Array - C#交换数组中的对象 - C#
【发布时间】:2010-09-01 03:16:03
【问题描述】:

在 C# 中,我有一个 MenuItem 数组。我正在尝试使用以下代码交换数组的索引 2 和索引 3 中的两个对象,但没有成功:

MenuItem Temp = Items[2];  
Items[2] = Items[3];  
Items[3] = Temp;  

第二行和第三行不能在 C# 中运行肯定是有原因的,我可能还不明白。有人能再澄清一点吗?我是否必须深入并单独交换对象中的每个属性?

已编辑 - 抱歉。看起来我在尝试清理代码以进行发布时弄乱了代码。现已更正。

实际代码是:

MenuItem TempButton = MenuItems.Items[SelectedButton.CountId];  
MenuItems.Items[SelectedButton.CountId] = MenuItems.Items[SelectedButton.CountId + 1];  
MenuItems.Items[SelectedButton.CountId + 1] = TempButton;  

MenuItems.ItemsMenuItem 的数组

查看我放在 MenuItems.Items 上的 Watch,第 2 行或第 3 行没有任何反应。

MenuItems.Items 属性具有 get 和 set 函数,这可能会导致问题...将进一步调查...

【问题讨论】:

  • 您的代码没有意义。您似乎将TempItems[2] 分配给彼此,实际上没有交换任何内容。
  • 您在第二行代码中引用MenuItems.Items[],而在其他任何地方引用Items[] 是否有原因?和第 2 行中的 SelectedButton.CountID,但其他任何地方的幻数?
  • 我想我确切地知道这里发生了什么。看我的回答。

标签: c# arrays object swap


【解决方案1】:

您将设置Items[2] 设置为Temp,一开始是Items[2],因此您实际上什么也没做。我不知道SelectedButton.CountId 应该是什么。

但如果你只想交换索引 2 和 3,你可以这样做:

Item Temp = Items[2];
Items[2] = Items[3];
Items[3] = Temp;

【讨论】:

    【解决方案2】:

    SelectedButton.CountId = 2?如果是这样,我会试试这个:

    Item Temp = MenuItems.Items[2];  
    MenuItems.Items[SelectedButton.CountId] = MenuItems.Items[3];  
    MenuItems.Items[3] = Temp;  
    

    注意最后一行有一个 3。

    这样会更清楚:

    Item Temp = MenuItems.Items[SelectedButton.CountId];  
    MenuItems.Items[SelectedButton.CountId] = MenuItems.Items[3];  
    MenuItems.Items[3] = Temp;  
    

    【讨论】:

      【解决方案3】:

      我不知道SelectedButton.CountId 应该是什么,但您将Temp 放回原来的位置。而MenuItems.Items 似乎是与Items 完全不同的集合。

      string[] items = { "one", "two", "three" };
      string temp = items[1]; // temp = "two"
      items[1] = items[2]; // items[1] = "three"
      items[2] = temp; // items[2] = "two"
      
      // items is now
      // { "one", "three", "two" }
      

      【讨论】:

        【解决方案4】:

        试试:

        Item Temp = Items[SelectedButton.CountId];   
        Items[SelectedButton.CountId] = MenuItems.Items[SelectedButton.CountId+1];   
        Items[SelectedButton.CountId+1] = Temp;  
        

        这应该以泡沫方式交换

        【讨论】:

          【解决方案5】:

          我记得前段时间遇到过类似的混淆来源,DataRow.ItemArray 属性。这个属性非常违反直觉,原因与您示例中的 Items 属性看起来很奇怪一样。

          最终令人困惑的是,该属性被设计为复制并分配给,就像您通常使用值类型的字段(如@ 987654324@、double 等)。也就是说,要更改索引 2 处的元素,这是行不通的:

          row.ItemArray[2] = "New Value";
          

          上面的代码实际上会将行中的值复制到一个新数组中,获取该副本并将索引 2 处的值设置为“新值”,然后新数组将立即变为超出范围。该属性假定的工作方式是:

          object[] items = row.ItemArray;
          items[2] = "New Value";
          row.ItemArray = items;
          

          非常违反直觉,在我的书中(图书馆开发人员注意:不要这样做)。但听起来这可能是您在代码中看到的问题背后的问题。

          换句话说,我认为您(现在)拥有的交换代码是正确的。问题出在谁有聪明的想法让Items 属性表现得好像它是一个值字段。

          【讨论】:

            【解决方案6】:

            我遇到了同样的问题,因为我想在 WPF-TreeView 中上下移动元素。由于没有一个答案能解决我的问题,所以这里是我能找到的最好的答案。

                private void MoveLayerUp()
                {
                    if(Layers.SelectedItem != null)
                    {
                        int index = Layers.Items.IndexOf(Layers.SelectedItem);
                        if (index > 0)
                        {
                            var swap = Layers.Items[index - 1];
                            Layers.Items.RemoveAt(index - 1);
                            Layers.Items.Insert(index, swap);
                        }
                    }
                }
            
                private void MoveLayerDown()
                {
                    if (Layers.SelectedItem != null)
                    {
                        int index = Layers.Items.IndexOf(Layers.SelectedItem);
                        if (index < Layers.Items.Count-1)
                        {
                            var swap = Layers.Items[index + 1];
                            Layers.Items.RemoveAt(index + 1);
                            Layers.Items.Insert(index, swap);
                        }
                    }
                }
            

            这解决了在集合中分配元素的问题。此外,它还有一个优点是当前选定的项目永远不会被触摸并保持选中状态。

            【讨论】:

              【解决方案7】:

              解决了这个问题。我觉得我把问题复杂化了一点。

              MenuItems.Items 是一个带有 get/set 函数的属性,它返回/设置一个私有 ArrayList。

              我在 MenuItems 的类中创建了一个函数,它交换了私有 ArrayList 中的索引。 (它使用的标准交换代码类似于我尝试过的以及每个人在回复中提到的。)

              感谢大家的帮助。

              【讨论】:

              • 是负责Items 属性的开发人员吗?如果是这样,我强烈建议您更改它,因为这种行为只会让其他开发人员在查看此代码时感到困惑。 (我假设你不是,但你说“我在课堂上创建了一个函数......”这一事实让我质疑这个假设。)
              • @DanTao 和负责上课的同事聊天。私有 ArrayList 包含不能从外部访问的数据。事实上,如果 ArrayList 被修改而没有像 AddItems()、RemoveItems() 等成员函数那样做的某些预防措施,那可能是灾难性的。该属性旨在返回该实例的内部数据副本,正如您所怀疑的那样,它立即超出了范围。
              • 数据的修改只能通过成员函数,所以我其实认为该属性应该真正变成一个返回相关数据的函数。我认为这会阻止其他开发人员假设他们可以(尝试)为其分配数据......
              • 是的,列表根本不应该以这种方式公开,尤其是set!公开您希望允许的行为:AddRemove 等。如果您想提供一种在不允许直接操作 ArrayList 的情况下获取项目的方法,例如 GetItems,它被明确记录为返回在我看来,项目的 副本Items 属性更好。
              猜你喜欢
              • 2014-12-06
              • 1970-01-01
              • 2012-08-05
              • 2016-03-04
              • 1970-01-01
              • 2017-09-04
              • 1970-01-01
              • 2022-01-18
              • 2011-01-15
              相关资源
              最近更新 更多