两个对象(一个在列表中<>)共享相同的内存地址,即如果一个对象被更改,它将更改列表中的另一个对象



我为此付出了很多努力和研究,但我被困住了。我尝试过复制构造函数、复制函数和成员克隆函数,但这些似乎都不起作用。Matrix[0]中的元素不应该改变,但g1的改变会改变。

如果有人知道如何解决此问题,请回复。

我正在添加其他文本,以便我可以发布我的问题。

class Game
{
public Game()
{
Card_ID = 1;
EmptyMainMonsterZones = 5;
EmptyExtraMonsterZones = 1;
EmptySpellTrapZones = 5;
LP = 8000;
NormalSummons = 1;
DrawnCards = 0;
LastEvent = "";
CardPool = new List<Card>();
ScenarioSteps = new List<string>();
}
public Game(Game other)
{
Card_ID = other.Card_ID;
EmptyMainMonsterZones = other.EmptyMainMonsterZones;
EmptyExtraMonsterZones = other.EmptyExtraMonsterZones;
EmptySpellTrapZones = other.EmptySpellTrapZones;
LP = other.LP;
NormalSummons = other.NormalSummons;
DrawnCards = other.DrawnCards;
LastEvent = other.LastEvent;
//CardPool = new List<Card>(other.CardPool);
CardPool = new List<Card>();
foreach (Card c in other.CardPool)
{
CardPool.Add(c);
}
//ScenarioSteps = new List<string>(other.ScenarioSteps);
ScenarioSteps = new List<string>();
foreach (string s in other.ScenarioSteps)
{
ScenarioSteps.Add(s);
}
}
public object Clone()
{
return this.MemberwiseClone();
}
int Card_ID;
public int EmptyMainMonsterZones;
public int EmptyExtraMonsterZones;
public int EmptySpellTrapZones;
public int LP;
public int NormalSummons;
public int DrawnCards;
public string LastEvent;
public List<Card> CardPool = new List<Card>();
public List<string> ScenarioSteps = new List<string>();
public void Init(string name,string location,string position = "-")
{
Card c = new Card(name);
if(location == "Main Monster Zone")
{
c.SetLocation(location);
EmptyMainMonsterZones--;
}
else if (location == "Extra Monster Zone")
{
c.SetLocation(location);
EmptyExtraMonsterZones--;
}
else
{
c.SetLocation(location);
c.SetPosition(position);
c.SetCard_ID(Card_ID);
Card_ID++;
CardPool.Add(c);
}
}
public void PrintScenarioSteps()
{
for(int i=0;i<ScenarioSteps.Count;i++)
{
Console.WriteLine(ScenarioSteps[i]);
}
}
public void Print()
{
for(int i=0;i<CardPool.Count;i++)
{
if(!CardPool[i].IsLocation("No Location"))
{
Console.WriteLine("{0} ({1}) is in the {2}", CardPool[i].getName(), CardPool[i].getLevel(), CardPool[i].getLocation());
}
}
}
// Checks
bool IsCanBeNormalSummoned(Card c)
{
if (c.IsLevelBelow(4) && c.IsLocation("Hand") && EmptyMainMonsterZones > 0 && NormalSummons > 0) return true;
if (c.IsException("Normal Summon without Tribute") && c.IsLocation("Hand") && EmptyMainMonsterZones > 0 && NormalSummons > 0) return true;
return false;
}
// Operations
public bool NormalSummon(ref Card c)
{
if(IsCanBeNormalSummoned(c))
{
c.SetPreviousLocation(c.getLocation());
c.NormalSummoned = true;
c.SetLocation("Main Monster Zone");
EmptyMainMonsterZones--;
NormalSummons--;
LastEvent = "Normal Summon";
if(!c.Negated)
{
if(c.IsName("Fusilier Dragon, the Dual-Mode Beast"))
{
c.SetAttack(c.getAttack()/2);
c.SetDefense(c.getDefense()/2);
}
}
return true;
}
return false;
}
}
class Program
{
static List<Game> Matrix = new List<Game>();
static void Main(string[] args)
{
Game Duel = new Game();
Duel.Init("Level Eater", "Hand");
Duel.Init("Junk Forward", "Hand");
Duel.Init("Fusilier Dragon, the Dual-Mode Beast","Hand");
Matrix.Add(Duel);
Game g1 = new Game(Matrix[0]);
Console.WriteLine("g1:");
g1.Print();
Console.WriteLine();
Console.WriteLine("Matrix[0]:");
Matrix[0].Print();
Console.WriteLine();
Card c1 = g1.CardPool[0];
if (g1.NormalSummon(ref c1))
{
string s = "Normal Summon " + g1.CardPool[0].getName() + ".";
g1.ScenarioSteps.Add(s);
Console.WriteLine("After Normal Summon:");
Console.WriteLine("g1:");
g1.Print(); // Pointing to the same address!!!
Console.WriteLine();
Console.WriteLine("Matrix[0]:");
Matrix[0].Print(); // This changes, too!!!
Console.WriteLine();
Matrix.Add(g1);
}
g1 = new Game(Matrix[0]);
if (Matrix[0].CardPool[0].IsLocation("Main Monster Zone")) Console.WriteLine("Yes, but I shouldn't be changed!");
if (g1.CardPool[0].IsLocation("Main Monster Zone")) Console.WriteLine("Yes!");
Card c2 = g1.CardPool[1];
if (g1.NormalSummon(ref c2))
{
string s = "Normal Summon " + g1.CardPool[1].getName() + ".";
g1.ScenarioSteps.Add(s);
g1.Print();
Console.WriteLine();
g1.CardPool[0].Print();
Console.WriteLine();
Matrix.Add(g1);
}
g1 = new Game(Matrix[0]);
Card c3 = g1.CardPool[2];
if (g1.NormalSummon(ref c3))
{
string s = "Normal Summon " + g1.CardPool[2].getName() + ".";
g1.ScenarioSteps.Add(s);
g1.Print();
Console.WriteLine();
Matrix.Add(g1);
}
Console.WriteLine("Matrix Count: " + Matrix.Count);
Console.ReadKey();
}
}

我建议使用一种方法来复制对象,而不是使用对另一个也将更新的对象的引用。可以将此方法添加到可为任何 Game 对象调用的 Game 类中。

序列化对象会将其转换为字符串,然后反序列化会将其更改回新对象(不引用原始对象(。

public Game Clone(Game other)
{
return JsonConvert.DeserializeObject<Game>(JsonConvert.SerializeObject(other));
}

这样做的作用是创建原始对象的新副本,更改此新对象中的任何内容都不会影响您拥有的原始列表或游戏对象。

你可以像这样使用上面的方法,

Game g1 = new Game().Clone(Matrix[0]);

您也可以在主程序中使用反序列化,

Game g1 = JsonConvert.DeserializeObject<Game>(JsonConvert.SerializeObject(Matrix[0]);

编辑:使用它来测试您的代码

我拿出了卡,因为它的实现不可用。除此之外,您的代码工作正常。不需要使用 ref,因为 C# 在作为参数传递时本机使用类的引用。

我的解决方案包括实现ICloneable接口并使用Clone方法,如下所示:

public object Clone()
{
return this.MemberwiseClone();
}

第二步是将你对象的副本传递给你的游戏构造函数,如你所见

Game g1 = new Game((Game)Matrix[0].Clone());

完整的代码如下:

static void Main(string[] args)
{
Game Duel = new Game();
Duel.Init("Level Eater", "Hand");
Duel.Init("Junk Forward", "Hand");
Duel.Init("Fusilier Dragon, the Dual-Mode Beast", "Hand");
Matrix.Add(Duel);
Game g1 = new Game((Game)Matrix[0].Clone());
Console.WriteLine("g1:");
g1.Print();
Console.WriteLine();
Console.WriteLine("Matrix[0]:");
Matrix[0].Print();
Console.WriteLine();
Card c1 = g1.CardPool[0];
if (g1.NormalSummon(ref c1))
{
string s = "Normal Summon " + g1.CardPool[0].getName() + ".";
g1.ScenarioSteps.Add("dsqdqdqdq");
Console.WriteLine("After Normal Summon:");
Console.WriteLine("g1:");
g1.Print(); // Pointing to the same address!!!
Console.WriteLine();
Console.WriteLine("Matrix[0]:");
Matrix[0].Print(); // This changes, too!!!
Console.WriteLine();
Matrix.Add(g1);
}
g1 = new Game((Game)Matrix[0].Clone());
if (Matrix[0].CardPool[0].IsLocation("Main Monster Zone")) Console.WriteLine("Yes, but I shouldn't be changed!");
if (g1.CardPool[0].IsLocation("Main Monster Zone")) Console.WriteLine("Yes!");
Card c2 = g1.CardPool[1];
if (g1.NormalSummon(ref c2))
{
string s = "Normal Summon " + g1.CardPool[1].getName() + ".";
g1.ScenarioSteps.Add(s);
g1.Print();
Console.WriteLine();
g1.CardPool[0].Print();
Console.WriteLine();
Matrix.Add(g1);
}
g1 = new Game((Game)Matrix[0].Clone());
Card c3 = g1.CardPool[2];
if (g1.NormalSummon(ref c3))
{
string s = "Normal Summon " + g1.CardPool[2].getName() + ".";
g1.ScenarioSteps.Add(s);
g1.Print();
Console.WriteLine();
Matrix.Add(g1);
}
Console.WriteLine("Matrix Count: " + Matrix.Count);
Console.ReadKey();
}
public class Game : ICloneable
{
public Game()
{
Card_ID = 1;
EmptyMainMonsterZones = 5;
EmptyExtraMonsterZones = 1;
EmptySpellTrapZones = 5;
LP = 8000;
NormalSummons = 1;
DrawnCards = 0;
LastEvent = "";
CardPool = new List<Card>();
ScenarioSteps = new List<string>();
}
public Game(Game other)
{
Card_ID = other.Card_ID;
EmptyMainMonsterZones = other.EmptyMainMonsterZones;
EmptyExtraMonsterZones = other.EmptyExtraMonsterZones;
EmptySpellTrapZones = other.EmptySpellTrapZones;
LP = other.LP;
NormalSummons = other.NormalSummons;
DrawnCards = other.DrawnCards;
LastEvent = other.LastEvent;
//CardPool = new List<Card>(other.CardPool);
CardPool = new List<Card>();
foreach (Card c in other.CardPool)
{
CardPool.Add(c);
}
//ScenarioSteps = new List<string>(other.ScenarioSteps);
ScenarioSteps = new List<string>();
foreach (string s in other.ScenarioSteps)
{
ScenarioSteps.Add(s);
}
}

int Card_ID;
public int EmptyMainMonsterZones;
public int EmptyExtraMonsterZones;
public int EmptySpellTrapZones;
public int LP;
public int NormalSummons;
public int DrawnCards;
public string LastEvent;
public List<Card> CardPool = new List<Card>();
public List<string> ScenarioSteps = new List<string>();
public void Init(string name, string location, string position = "-")
{
Card c = new Card(name);
if (location == "Main Monster Zone")
{
c.SetLocation(location);
EmptyMainMonsterZones--;
}
else if (location == "Extra Monster Zone")
{
c.SetLocation(location);
EmptyExtraMonsterZones--;
}
else
{
c.SetLocation(location);
c.SetPosition(position);
c.SetCard_ID(Card_ID);
Card_ID++;
CardPool.Add(c);
}
}
public void PrintScenarioSteps()
{
for (int i = 0; i < ScenarioSteps.Count; i++)
{
Console.WriteLine(ScenarioSteps[i]);
}
}
public void Print()
{
for (int i = 0; i < CardPool.Count; i++)
{
if (!CardPool[i].IsLocation("No Location"))
{
Console.WriteLine("{0} ({1}) is in the {2}", CardPool[i].getName(), CardPool[i].getLevel(), CardPool[i].getLocation());
}
}
}
// Checks
bool IsCanBeNormalSummoned(Card c)
{
if (c.IsLevelBelow(4) && c.IsLocation("Hand") && EmptyMainMonsterZones > 0 && NormalSummons > 0) return true;
if (c.IsException("Normal Summon without Tribute") && c.IsLocation("Hand") && EmptyMainMonsterZones > 0 && NormalSummons > 0) return true;
return false;
}
// Operations
public bool NormalSummon(ref Card c)
{
if (IsCanBeNormalSummoned(c))
{
c.SetPreviousLocation(c.getLocation());
c.NormalSummoned = true;
c.SetLocation("Main Monster Zone");
EmptyMainMonsterZones--;
NormalSummons--;
LastEvent = "Normal Summon";
if (!c.Negated)
{
if (c.IsName("Fusilier Dragon, the Dual-Mode Beast"))
{
c.SetAttack(c.getAttack() / 2);
c.SetDefense(c.getDefense() / 2);
}
}
return true;
}
return false;
}
public object Clone()
{
return this.MemberwiseClone();
}
}

最新更新