简体   繁体   中英

c# how to retrive objects as values from array

I am trying to create a simple 'inventory' system that stores items with the key being an items name, and with the remaining information being stored as a value. However, I am having difficulty figuring out how to then read the information. For example, if I have say a list of 10 items, and I want to select the items 'type' information from the key 'television' outlined below, how could I do this?

television {large, 5, 3, false, dynamic, 0.8, 20}

Hashtable myItems = new Hashtable();    

protected virtual bool OnAttempt_AddItem(object args) {
            object[] arr = (object[])args;
            string ItemType = (string)arr[0];
            string ItemName = (string)arr[1];
            int ItemAmount = (arr.Length == 2) ? (int)arr[2] : 1;
            int ItemACanHave = (arr.Length == 3) ? (int)arr[3] : 1;
            bool ItemClear = (bool)arr[4];
            string ItemEffect = (string)arr[5];
            float ItemModifier = (float)arr[6];
            int ItemWeight = (int)arr[7];

            // enforce ability to have atleast 1 item of each type
            ItemACanHave = Mathf.Max(1, ItemACanHave);

            myItems[ItemName] = new object[] {ItemType, ItemAmount, ItemACanHave, ItemClear, ItemEffect, ItemModifier, ItemWeight };    

            return true;    
        }

Create an item class to encapsulate the properties:

public class InventoryItem
{
    public string Name;
    public string Type;
    public int Amount;
    public int CanHave; // you should consider renaming this - it's very unclear what this could mean
    public bool Clear;
    public string Effect;
    public float Modifier;
    public int Weight;
}

Then you can use a Dictionary to store items:

Dictionary<string, InventoryItem> inventory = new Dictionary<string, InventoryItem>();

inventory["television"] = new InventoryItem 
                                { 
                                     Name = "television", Type = "large", Amount = 5,
                                     CanHave = 3, Clear = false, Effect = "dynamic",
                                     Modifier = 0.8, Weight = 20
                                });

And you can look it up like this:

Console.WriteLine("Type of television is: ", inventory["television"].Type);

I would suggest you to consider the possibility of more than one item of a certain type in a inventory list, ie two or more television sets instead of only one.

Use a base class and derived classes:

public class InventoryItem
{
    public string ItemType { get; set; }
    public string ItemName { get; set; }
    public int ItemAmount { get; set; }
    public int ItemACanHave { get; set; }
    public bool ItemClear { get; set; }
    public string ItemEffect { get; set; }
    public float ItemModifier { get; set; }
    public int ItemWeight { get; set; }
}

public class Radio : InventoryItem
{
}

public class Television : InventoryItem
{
}

// TODO: add your derived classes

Use a List<InventoryItem> to store the collection:

List<InventoryItem> InventoryItems = new List<InventoryItem>();

Modify your method (don't forget to add exception handling, as sometimes you might get different input than the one you expected in the args object):

protected virtual bool OnAttempt_AddItem(object args)
{
    // TODO: handle unboxing exceptions, size of the array etc
    //
    try
    {
        object[] arr = (object[])args;
        switch (arr[0].ToString().ToLower())
        {
            // TODO: add other types (Radio etc)
            case "television":
                var tv = new Television();
                tv.ItemType = (string)arr[0];
                tv.ItemName = (string)arr[1];
                tv.ItemAmount = (arr.Length == 2) ? (int)arr[2] : 1;
                tv.ItemACanHave = (arr.Length == 3) ? (int)arr[3] : 1;
                tv.ItemClear = (bool)arr[4];
                tv.ItemEffect = (string)arr[5];
                tv.ItemModifier = (float)arr[6];
                tv.ItemWeight = (int)arr[7];

                // enforce ability to have atleast 1 item of each type
                tv.ItemACanHave = Math.Max(1, tv.ItemACanHave);
                InventoryItems.Add(tv);
                break;
            default:
                var genericItem = new InventoryItem();
                genericItem.ItemType = (string)arr[0];
                genericItem.ItemName = (string)arr[1];
                genericItem.ItemAmount = (arr.Length == 2) ? (int)arr[2] : 1;
                genericItem.ItemACanHave = (arr.Length == 3) ? (int)arr[3] : 1;
                genericItem.ItemClear = (bool)arr[4];
                genericItem.ItemEffect = (string)arr[5];
                genericItem.ItemModifier = (float)arr[6];
                genericItem.ItemWeight = (int)arr[7];

                // enforce ability to have atleast 1 item of each type
                genericItem.ItemACanHave = Math.Max(1, genericItem.ItemACanHave);
                InventoryItems.Add(genericItem);
                break;
            //handle other cases
        }
        return true;
    }
    catch (Exception ex)
    {
        // log the error
        return false;
    }
}

Retrieve the filtered items like this:

var largeTvType = inventory.InventoryItems.OfType<Television>()
    // filter by type (or other criteria)
    .Where(tv => tv.ItemType == "large")
    // select only the property your interested in (in the case below
    // it will be always "television" because that's part of the 
    // logic inside the OnAttempt_AddItem method's switch statement)
    .Select(tv => tv.ItemType);

Still, as ChrisWue suggested in his answer, if you know that your inventory lists will be very large, I'd recommend you to use a Dictionary<string, InventoryItem> , the string key being a unique inventory item identifier. It will be faster.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM