0

So I have a static item list which stores a few classes, and in those classes are variables such as "int ID", "string name", "string description", "int currentAmount", etc.

ItemDatabase.cs...

public static List<Item> Items

static void LoadItemData()
{
    Items.Add(new item);
    ...
}

I then have a separate item list which will have items added to it for use by the player.

Player.cs...

List<Item> playerItems;

Then in other classes, I have AddItem(int ID) methods:

void AddItem(int id)
{
    foreach (Item i in ItemDatabase.Items)
        if (i.ID == id)
            playerItems.Add(i);
}

I'm currently adding in entities that will make use of the same data. But when I modify the Item added to the playerItems, it modifies ItemDatabase.Items (Obviously, due to referencing).

I can't make the Item class into a struct, because I have other classes which derive from it. I need the "currentAmount" integer to be by value. Is there any way I can do this?

P.S., I've tried deep cloning, and that doesn't play nicely with my Item class.

Shyy Guy
  • 232
  • 3
  • 18
  • 1
    Why doesn't cloning work? Seems like that's the solution. Can you shallow clone if you're just modifying value types (`string`,`int`)? – D Stanley Feb 04 '15 at 20:16
  • @DStanley, I tried to do a deep clone, inserting [Serializable] attributes at the top of each class, however other classes that I don't have control of like Texture2D were giving me that. I also have other classes inside the Item class. Wouldn't they be set to null if I didn't do a deep copy? – Shyy Guy Feb 04 '15 at 20:26
  • 1
    You don't _need_ to serialize to do a deep clone - serializing and deserializing is just one way. If you're not changing reference types then I would just do a shallow clone (either manually copying property vlaues or using [`object.MemberwiseClone`](https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone%28v=vs.110%29.aspx) – D Stanley Feb 04 '15 at 20:31
  • @DStanley, thank you so much. I tried MemberwiseClone, and it worked excellent. Do you mind putting that as an answer? – Shyy Guy Feb 04 '15 at 21:36

4 Answers4

1

You need to separate out currentAmount. Since that value only makes sense in the context of a Player anyways, I would take that out of the Item class, and use a Dictionary<Item,int> to keep track of the inventory:

Dictionary<Item, int> inventory = new Dictionary<Item, int>();

void AddItem(int id)
{
    foreach (Item i in ItemDatabase.Items)
        if (i.ID == id)
            playerItems.Add(i, 0); //Or whatever count
}
BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
1

Obviously you need to clone the objects if you want to change them without affecting the original. Serialization is one way to do a "deep clone" but as you have discovered not all types can be serialized.

If you are just modifying the first-level value type properties (not changing related item's values or references) you can use object.MemberwiseClone to create a shallow copy (copies of value types and references).

D Stanley
  • 149,601
  • 11
  • 178
  • 240
0

I'm still not sure where you are modifying ItemsDatabase.Items (currentAmount as property of the Entity doesn't makes much more sense), but for current amount in your Inventory, I guess this will help you:

Dictionary<Item, int> inventory = new Dictionary<Item, int>();

void AddItem(int id)
{
    foreach (Item i in ItemDatabase.Items)
        if (i.ID == id)
            {
              if(!inventory.Keys.Contains(i)){iventory.Add(i, 0);}
              inventory[i]+=1; //increment the amount of items in inventory.
            }
}

Important:

Dictionary uses Hash to get the object from dictionary, so, you probably want to override that method in your Item class:

class Item {
    public string Name;
    public string Description;
    public int currentAmount;

    public override int GetHashCode(){
       return Name.GetHashCode() + Description.GetHashCode();
    }
}

see more:

Community
  • 1
  • 1
celerno
  • 1,367
  • 11
  • 30
0

do this:

void AddItem(int id)
{
    var item = ItemDatabase.Items.FirstOrDefault(x=> x.ID == id);
    if(item!=null){
        playerItems.Add(new Item(){ ID = item.ID, Name = item.Name, etc... })
    }
}
aleha_84
  • 8,309
  • 2
  • 38
  • 46