在数组中交换对象 - C#

4

在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.Items 是一个 MenuItem 数组。

查看我放在 MenuItems.Items 上的监视器,第二行或第三行没有任何反应。

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


你的代码没有意义。你似乎将TempItems[2]互相赋值,实际上什么都没有交换。 - BoltClock
2
代码的第二行中为什么您要引用 MenuItems.Items[],而其他地方都是 Items[]?还有第二行中的SelectedButton.CountID,但其他地方都是用魔数吗? - Robert Harvey
我想我知道这里发生了什么。请看我的答案。 - Dan Tao
7个回答

3
您正在将Items[2]设置为Temp,而Items[2]一开始就是Temp,所以实际上您没有做任何事情。我不知道SelectedButton.CountId应该是什么。
但如果您只想交换索引2和3,可以这样做:
Item Temp = Items[2];
Items[2] = Items[3];
Items[3] = Temp;

1

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;  

1

我不知道SelectedButton.CountId应该是什么,但你把Temp放回了它最初的位置。而且MenuItems.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" }

1

尝试:

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

这应该以冒泡方式交换


1

我记得有一段时间我也遇到了类似的困惑,与 DataRow.ItemArray 属性有关。正是因为你的示例中的 Items 属性看起来如此奇怪,所以这个属性极其令人费解。

最终令人困惑的是,该属性被设计为可以像值类型(如 intdouble 等)的字段一样进行复制和赋值。也就是说,要更改索引为 2 的元素,这样是行不通的:

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

以上代码本质上会将行中的值复制到一个新数组中,然后将该副本并将索引2处的值设置为“New Value”,然后新数组将立即超出范围。这个属性原本应该是这样工作的:
object[] items = row.ItemArray;
items[2] = "New Value";
row.ItemArray = items;

非常不直观,在我的书里(给图书馆开发人员的备注:不要这样做)。但听起来这可能是你在代码中遇到的问题背后的原因。
换句话说,我认为你现在所拥有的交换代码是正确的。问题出在那个聪明的人将那个Items属性当作值字段来操作。

0

我遇到了与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);
            }
        }
    }

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

-1
解决了这个问题。我觉得我把问题复杂化了。
MenuItems.Items是一个具有获取/设置功能的属性,它返回/设置一个私有ArrayList。
我在MenuItems类中创建了一个函数,用于交换私有ArrayList中的索引(使用标准的交换代码,类似于我尝试过的和其他人在回复中提到的)。
感谢大家的帮助。

你是负责 Items 属性的开发人员吗?如果是的话,我强烈建议你更改它,因为这种行为只会让其他开发人员在查看此代码时感到困惑。(我假设你不是,但是你说“我在类中创建了一个函数...”这一事实让我对这个假设产生了疑问。) - Dan Tao
@DanTao 与负责该类的同事进行了交谈。私有的 ArrayList 包含的数据不应从外部访问。实际上,如果在没有某些预防措施的情况下修改 ArrayList,可能会造成灾难性后果,而像 AddItems()、RemoveItems() 等成员函数则提供了这些预防措施。该属性旨在返回该实例内部数据的副本,正如您所怀疑的那样,它立即超出范围。 - tbv
数据的修改应该只能通过成员函数进行,因此我认为这个属性实际上应该被转换为一个返回相关数据的函数。我认为这样可以防止其他开发人员假设他们可以(尝试)向其分配数据... - tbv
是的,列表不应该以这种方式公开,特别是使用 set!公开您想要允许的行为:AddRemove等。如果您想提供一种获取项目的方法,而不允许直接操作 ArrayList,那么像 GetItems 这样的东西就会比 Items 属性更好,因为它明确记录了返回项目的 副本 - Dan Tao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接