更新类中的对象数组会更新其他对象中的数组

时间:2014-04-05 21:43:45

标签: c# arrays class reference-type

我已经搜索了可能导致意外输出的原因(至少对我来说)并且我没有走得太远。我认为它与类作为引用类型有关,但我很困惑,因为你会看到下面的输出显示我期望的字符串,但是数组的内容似乎是更新引用而不是值?我糊涂了。我已将代码删除到以下内容。基本上我有一个未知数量的“球员”,还有更多的属性,然后我在这里展示。每个“玩家”都有“装备”,实际上总共有24件。

我在这里使用了一个数组,因为我希望能够在阵列中的同一个索引处比较不同玩家的设备。

public class Equipment
{
    public int PropA { get; set; }
    public int PropB { get; set; }

    public Equipment ()
    {
        PropA = 0;
        PropB = 0;
    }

    public Equipment (Equipment eq)
    {
        PropA = eq.PropA;
        PropB = eq.PropB;
    }
}

public class Player
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Equipment[] Equip = new Equipment[2];

    public Player ()
    {
        FirstName = "";
        LastName = "";

        for (int i=0; i<Equip.Length; i++)
        {
            this.Equip[i] = new Equipment();
        }
    }

    public Player (Player p)
    {
        FirstName = p.FirstName;
        LastName = p.LastName;

        for (int i=0; i<p.Equip.Length; i++)
        {
            this.Equip[i] = p.Equip[i];
        }
    }
}

public void LoadPlayers()
{
    Player tmpPlayer = new Player();

    List<Player> PlayerList = new List<Player>();

    tmpPlayer.FirstName = "One";
    tmpPlayer.LastName = "Two";

    tmpPlayer.Equip[0].PropA = 1;
    tmpPlayer.Equip[0].PropB = 2;

    tmpPlayer.Equip[1].PropA = 3;
    tmpPlayer.Equip[1].PropB = 4;

    PlayerList.Add(new Player(tmpPlayer));

    tmpPlayer.FirstName = "Three";
    tmpPlayer.LastName = "Four";

    tmpPlayer.Equip[0].PropA = 5;
    tmpPlayer.Equip[0].PropB = 6;

    tmpPlayer.Equip[1].PropA = 7;
    tmpPlayer.Equip[1].PropB = 8;

    PlayerList.Add(new Player(tmpPlayer));

    foreach (Player p in PlayerList)
    {
        Console.WriteLine(p.FirstName);
        Console.WriteLine(p.LastName);

        Console.WriteLine(p.Equip[0].PropA.ToString());
        Console.WriteLine(p.Equip[0].PropB.ToString());
        Console.WriteLine(p.Equip[1].PropA.ToString());
        Console.WriteLine(p.Equip[1].PropB.ToString());
    }
}

这是我得到的输出:

一 二 五 6 7 8 三 四 五 6 7 8

这是我预期的输出:

一 二 1 2 3 4 三 四 五 6 7 8

除了指出我的错误之外,还有一种明显更好的方法来实现我的目标吗?

提前感谢您,我感谢您的帮助!

3 个答案:

答案 0 :(得分:1)

您需要更改

public Equipment[] Equip = new Equipment[1]; 

public Equipment[] Equip = new Equipment[2];,否则您将获得IndexOutOfRangeException

在你的LoadPlayers方法中,你正在修改Player的同一个实例,而不是创建一个新的播放器。所以你得到相同的输出,因为你只有一个实例。创建一个新实例然后添加它列在你的名单上。

Player tmpPlayer = new Player();

/* set the properties */

PlayerList.Add(new Player(tmpPlayer));

tmpPlayer = new Player();

/* set the properties */

PlayerList.Add(new Player(tmpPlayer));

你应该得到你期望的输出。

答案 1 :(得分:1)

问题是您只设置了对象tmpPlayer的一个实例,并在您第二次尝试设置其参数时覆盖了对象中的值。

您可以尝试而不是制作一个对象,然后在整个时间内更改它并遇到内存引用问题,每次都可以将新对象放入数组中,并在添加对象时设置其属性。你应该能够像这样实现它

PlayerList.Add(new Player()
{
    FirstName = "One";
    LastName = "Two";

    Equip[0].PropA = 1;
    Equip[0].PropB = 2;

    Equip[1].PropA = 3;
    Equip[1].PropB = 4;
});

PlayerList.Add(new Player()
{
    FirstName = "Three";
    LastName = "Four";

    Equip[0].PropA = 5;
    Equip[0].PropB = 6;

    Equip[1].PropA = 7;
    Equip[1].PropB = 8;
});

有了这个,每个对象都应该是唯一的,希望你能得到你想要的输出。

答案 2 :(得分:1)

问题是您的复制构造函数public Player (Player p)会将复制的播放器的设备分配给新播放器。由于您使用此构造函数创建实际放入列表中的两个玩家,因此他们的设备都指的是原始玩家tmpPlayer的设备。

您可以通过让复制构造函数执行设备的副本来解决此问题:

public Player (Player p)
{
    FirstName = p.FirstName;
    LastName = p.LastName;

    for (int i=0; i<p.Equip.Length; i++)
    {
        this.Equip[i] = new Equipement(p.Equip[i]);
    }
}