0

Let's say I have the following structs:

using System;
using System.Collections.Generic;

protected struct Inventory
    {
        private struct InventorySlot
        {
            public InventorySlot(int numItems, int containsId)
            {
                NumItems = numItems;
                ContainsId = containsId;
            }
            public int NumItems { get; private set; }

            public void AddItem()
            {
                NumItems += 1;
            }

            public void DeleteItem()
            {
                NumItems -= 1;
            }
        }


        private int NumSlots;
        private List<InventorySlot> InventorySlots { get; set; }

        public Inventory(int numSlots)
        {
            NumSlots = numSlots;
            InventorySlots = new List<InventorySlot>(NumSlots);
        }

        public void AddItem(int ItemId)
        {
            if (InventorySlots.Exists(slot => slot.ContainsId == ItemId))
            {
                InventorySlot insertSlot = InventorySlots.FindLast(slot => slot.ContainsId == ItemId);
                insertSlot.AddItem();
            }
            else
            {
                InventorySlots.Add(new InventorySlot(1, ItemId));
            }
            for (int i = 0; i < InventorySlots.Count; i++)
            {
                print("inventorySlot " + i + ":" + InventorySlots[i].NumItems);
            }
        }

        public void DeleteItem(int inventorySlotIndex)
        {
            try
            {
                InventorySlots[inventorySlotIndex].DeleteItem();
            }
            catch (Exception ex)
            {
                throw new Exception("Fehler beim Löschen eines Items: " + ex.Message);
            }
        }
    } 

Then I expect the following code to increase/decrease PlayerInventory.InventorySlots[0].NumItems by 1. after it creates the first InventorySlot List entry.


private Inventory PlayerInventory = new Inventory(9);

public void AddDelete()
{
      PlayerInventory.AddItem(ItemId: 1);
      PlayerInventory.DeleteItem(inventorySlotIndex: 0);  
}

My problem is as following: Every time I call either Inventory.AddItem() or Inventory.DeleteItem() the code enters the corresponding function of InventorySlot, changes NumItems but when it returns, NumItems equals 1 again. What am I missing?

Nayangar
  • 139
  • 10
  • Your second block of code: What kind of class is that part of? – Gabriel Luci Jun 10 '20 at 15:46
  • 3
    `InventorySlot insertSlot = InventorySlots.FindLast` gives you a copy of the `InventorySlot` in your list. You are then modifying that copy, not the item in the list – UnholySheep Jun 10 '20 at 15:49
  • Ah...the classic [struct vs. class](https://stackoverflow.com/questions/13049/whats-the-difference-between-struct-and-class-in-net) mistake. It never gets old?... – Idle_Mind Jun 10 '20 at 16:21
  • @GabrielLuci the same class that contains ```Inventory``` from the first code block. The class is public – Nayangar Jun 11 '20 at 18:43

1 Answers1

0

The problem here is that structs are value types, but you're expecting it to act as a reference type. Value types are passed "by value", which means a new object is created during an assignment (whereas a reference to the same object is created when a reference type is assigned).

So when we call FindLast below, it finds the last item, creates a copy of it, and assigns the copy to insertSlot. Then when we call insertSlot.AddItem(), we are calling it on a different instance than the one located in InventorySlots.

InventorySlot insertSlot = InventorySlots.FindLast(slot => slot.ContainsId == ItemId);
insertSlot.AddItem();

To resolve this issue, use class instead of struct and it should behave as expected.

Rufus L
  • 36,127
  • 5
  • 30
  • 43