c# - 设置一个对象等于另一个对象C#时如何影响原始对象的属性
问题描述
制作一个文本游戏来练习编码并遇到一个非常奇怪的问题。我对此进行了搜索,但大多数人都试图将一个对象克隆到另一个对象,而我试图将对象 B 指向对象 A,因为我想更改同一个对象的属性。
public Armor Player_Chest_Armor { get; set; }
public Armor Player_Head_Armor { get; set; }
public Armor Player_Legs_Armor { get; set; }
public Weapon Player_Weapon { get; set; }
public Spell Player_Spell { get; set; }
public List<Consumable> Consumables { get; set; }
public List<IEquipment> Inventory { get; set; }
[JsonConstructor]
public Player (string name) {
this.Name = name;
this.Consumables = new List<Consumable>();
this.Inventory = new List<IEquipment>();
this.Inventory.Add(new Weapon("bronze sword", 22, 28, 25, 1.2, false));
this.Inventory.Add(new Armor("bronze chestplate", Armor.ArmorSlot.Chest, 35, 10, 20, false));
this.Inventory.Add(new Armor("bronze helmet", Armor.ArmorSlot.Head, 12, 3, 7, false));
this.Inventory.Add(new Armor("bronze legplates", Armor.ArmorSlot.Legs, 20, 5, 10, false));
this.Consumables.Add(new Consumable("minor health potion", 3, Consumable.PotionType.Health, 50));
this.Consumables.Add(new Consumable("minor mana potion", 3, Consumable.PotionType.Mana, 50));
this.Player_Spell = new Spell("Fireball", 50, 0, 1);
}
public void EquipInitialGear() {
this.EquipWeapon(this.Inventory[0] as Weapon);
this.EquipArmor(this.Inventory[1] as Armor);
this.EquipArmor(this.Inventory[2] as Armor);
this.EquipArmor(this.Inventory[3] as Armor);
}
public void DecreaseArmorDurability() {
try {
this.Player_Chest_Armor.DecreaseDurability();
}
这是我的播放器类中代码的相关部分。Player_ 无论是玩家装备的东西,无论是盔甲、武器等。我使用 IEquipment 接口将盔甲和武器对象连接到一个列表中,因为玩家库存应该包括所有东西。创建玩家时,EquipWeapon 和 EquipArmor 方法调用将这些库存索引对象设置为适当的玩家盔甲/武器槽。下面的代码,为了简单起见,假设没有武器已经装备,所以它直接进入 this.Player_Weapon = 武器行。
public void EquipWeapon(Weapon weapon) {
if (weapon.IsEquipped() == true) {
Console.WriteLine("You have already equipped {0}.", weapon.GetName());
return;
}
try {
if (this.Player_Weapon.Equipped == true) {
this.UnequipWeapon(this.Player_Weapon);
}
}
catch(NullReferenceException) {}
this.Player_Weapon = weapon;
weapon.Equipped = true;
Console.WriteLine("You have equipped {0}.", this.Player_Weapon.GetName());
}
当我尝试更改 Player_Weapon 的属性值时,它会针对该对象发生更改,但库存中的对象(应该相同)具有原始属性值。降低耐久度在武器类中执行以下操作:
public void DecreaseDurability() {
this.Durability -= 1;
}
每一轮攻击,我都会调用这个方法来将武器的耐久度降低 1 到 100。在调试模式下,我可以看到 this.Player_Weapon.Durability 从 100 到 99。但是,如果我去看看库存中应该是同一个对象,它的持久性是 100,这让我认为它正在创建对象的副本而不是引用原始对象。
我确信这是一个指针问题,但我只是看不出问题出在哪里。我希望对 Player_Weapon 属性的更改也影响对库存中该武器应指向的同一对象的更改。
为清楚起见进行了编辑:玩家、武器和盔甲都是类,而不是结构。
解决方案
这是JSON保存游戏文件。这个错误是如此阴险,以至于我向 SO 寻求帮助的原因是它工作正常,但是当我退出在 JSON 中创建自动保存的游戏时,它会存储对象数据。但是,Player_Weapon 和任何 Player_Armor 都是指向库存中物品的类指针。只要程序正在运行,它就可以正常工作。创建 JSON 并保存数据后,Player 类实例似乎与库存分离。这是保存在文件中的内容:
"Player_Chest_Armor": {
"Name": "bronze chestplate",
"ArmorCategory": 1,
"ItemValue": 35,
"ArmorRating": 12,
"Equipped": true,
"Durability": 98
},
"Player_Head_Armor": {
"Name": "bronze helmet",
"ArmorCategory": 0,
"ItemValue": 12,
"ArmorRating": 6,
"Equipped": true,
"Durability": 98
},
"Player_Legs_Armor": {
"Name": "bronze legplates",
"ArmorCategory": 2,
"ItemValue": 20,
"ArmorRating": 8,
"Equipped": true,
"Durability": 98
},
"Player_Weapon": {
"Name": "notched axe",
"RegDamage": 16,
"ItemValue": 10,
"CritMultiplier": 1.2,
"Equipped": true,
"Durability": 98
},
"Player_Spell": {
"Name": "Fireball",
"ManaCost": 50,
"Level": 1,
"SpellCategory": 0,
"FireOffense": {
"BlastDamage": 30,
"BurnDamage": 5,
"BurnCurRounds": 3,
"BurnMaxRounds": 3
}
},
"Consumables": [
{
"Name": "minor health potion",
"Quantity": 1,
"ItemValue": 3,
"Equipped": false,
"PotionCategory": 0,
"RestoreHealth": {
"RestoreHealthAmt": 50
}
},
{
"Name": "minor mana potion",
"Quantity": 1,
"ItemValue": 3,
"Equipped": false,
"PotionCategory": 1,
"RestoreMana": {
"RestoreManaAmt": 50
}
}
],
"Inventory": [
{
"$type": "DungeonGame.Weapon, DungeonGame",
"Name": "bronze sword",
"RegDamage": 27,
"ItemValue": 25,
"CritMultiplier": 1.2,
"Equipped": false,
"Durability": 98
},
{
"$type": "DungeonGame.Armor, DungeonGame",
"Name": "bronze chestplate",
"ArmorCategory": 1,
"ItemValue": 35,
"ArmorRating": 12,
"Equipped": true,
"Durability": 98
},
{
"$type": "DungeonGame.Armor, DungeonGame",
"Name": "bronze helmet",
"ArmorCategory": 0,
"ItemValue": 12,
"ArmorRating": 6,
"Equipped": true,
"Durability": 98
},
{
"$type": "DungeonGame.Armor, DungeonGame",
"Name": "bronze legplates",
"ArmorCategory": 2,
"ItemValue": 20,
"ArmorRating": 8,
"Equipped": true,
"Durability": 98
},
{
"$type": "DungeonGame.Weapon, DungeonGame",
"Name": "notched axe",
"RegDamage": 16,
"ItemValue": 10,
"CritMultiplier": 1.2,
"Equipped": true,
"Durability": 98
}
]
}
正如保存游戏文件中的数据所示,没有对 Player Weapon/Armor 类数据的库存项目的引用,因此当游戏重新加载数据时,它会将这些对象与库存中的原始对象分离。Player Weapon/Armor 设置为这些值,但它不再引用库存中这些类的实例,因此它正在创建对象的副本。
保存的游戏代码正在通过序列化创建一个 JSON 文件。从https://www.newtonsoft.com/json/help/html/PreserveObjectReferences.htm,“默认情况下,Json.NET 将按值序列化它遇到的所有对象”。
保留引用的解决方案似乎是使用以下代码声明和初始化 json:
string json = JsonConvert.SerializeObject(people, Formatting.Indented,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects });
我之前没有使用 PreserveReferencesHandling,这导致了这个错误。
推荐阅读
- reactjs - 酶的安装第二次失败
- blockchain - 与区块链网络同步的问题
- uipath - Uipath - 如何从 pdf 中提取表格
- string - 你可以自定义@info 颜色吗?
- android - Android如何在带有数据绑定的文本视图中使用字符串变量
- python - 盈透证券 - 未找到请求的安全定义
- amazon-web-services - 从 Secrets Manager 映射 AWS API Gateway HTTPIntegration 标头
- qt - 分配给已经在 QML 中定义的绑定的属性是否合法
- python-3.x - Python从简单图像中提取数字
- javascript - 如何在反应和提取数据中向制表器添加行