Обновление массива объектов в массивах обновлений классов в других объектах

115
9

Я искал, что может вызвать неожиданный выход (по крайней мере для меня), и у меня не так далеко. Я думаю, что это связано с тем, что классы являются ссылочным типом, но я смущен, так как вы увидите, что результат ниже показывает строки, поскольку я ожидаю, однако содержимое массива, похоже, обновляет ссылку, а не значение? Я смущен. Я отключил свой код до следующего. В основном у меня есть неизвестное количество "игроков", со многими другими свойствами, которые я здесь показал. У каждого "игрока" есть куски "экипировки", на самом деле всегда есть 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());
}
}

Это результат, который я получаю:

Один Два 5 6 7 8 Три Четыре 5 6 7 8

Это ожидаемый результат:

Один Два 1 2 3 4 Три Четыре 5 6 7 8

Помимо указания моей ошибки, есть ли очевидный лучший способ достижения моей цели?

Заранее спасибо, я ценю любую помощь!

спросил(а) 2014-04-06T00:43:00+04:00 6 лет, 6 месяцев назад
1
Решение
58

Вам нужно изменить

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

И вы должны получить ожидаемый результат.

ответил(а) 2014-04-06T00:52:00+04:00 6 лет, 6 месяцев назад
58

Привет, проблема в том, что вы устанавливаете только один экземпляр объекта 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;
});

При этом каждый объект должен быть уникальным, и, надеюсь, вы получите желаемый результат.

ответил(а) 2014-04-06T00:55:00+04:00 6 лет, 6 месяцев назад
58

Проблема заключается в том, что ваш конструктор копирования, 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]);
}
}

ответил(а) 2014-04-06T00:55:00+04:00 6 лет, 6 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема