2013-05-13 2 views
0

Я пытаюсь создать простую систему «инвентаря», в которой хранятся элементы с ключом, являющимся именем элемента, а оставшаяся информация хранится как значение. Однако мне трудно понять, как читать информацию. Например, если я скажу список из 10 элементов, и я хочу выбрать информацию о типе элементов из приведенного ниже ключевого «телевизора», как я могу это сделать?C# как извлекать объекты как значения из массива

телевидение {большой, 5, 3, ложная, динамика, 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;  
     } 
+1

Есть ли причина, по которой вы по-прежнему используете не-общую коллекцию «Hashtable» вместо «Словарь <,>'? (Похоже, что вы должны создавать класс 'Item' для инкапсуляции всех этих значений btw.) –

+0

Не использовали HashTable, однако есть ли проблемы с использованием самоопределяемого класса сущностей? – Fendy

+0

Я довольно новичок в C# и его типах массивов. Если есть лучший метод, я бы очень признателен, если бы кто-нибудь мог познакомить меня с этим. –

ответ

1

Создать класс элемента, чтобы инкапсулировать свойства:

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; 
} 

Тогда вы можете используйте словарь для хранения предметов:

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 
           }); 

И вы можете посмотреть его, как это:

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

вы забыли про ключ в своем инвентаре. Добавить – JleruOHeP

+0

@JleruOHeP: Спасибо, исправлено – ChrisWue

+0

Просто любопытно - есть ли какие-либо преимущества использования поля против авто-недвижимости в вашем классе? – Tommi

1

Я хотел бы предложить вам рассмотреть возможность более одного элемента определенного типа в списке инвентаризации, то есть два или более телевизоров, а не только один.

Используйте базовый класс и производные классы:

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 

Используйте List<InventoryItem> для хранения коллекции:

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

Измените метод (не забудьте добавить обработку исключений, а иногда может получить различный ввод, чем тот, который вы ожидали в объекте args):

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; 
    } 
} 

Получить отфильтрованные элементы, как это:

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); 

Тем не менее, как и ChrisWue предложил в своем ответе, если вы знаете, что ваши инвентарные списки будут очень большие, я бы рекомендовал вам использовать Dictionary<string, InventoryItem>, ключ string являющийся уникальным идентификатором товарной единицы. Это будет быстрее.

+0

Могу ли я получить объяснение различий между этим методом и @ChrisWue? –

+0

Основное отличие заключается в использовании List вместо Dictionary. Я не думаю, что это хорошая идея, если вы хотите получить предметы по ключевым словам. Сложность поиска слова - O (1), тогда как запрос LINQ будет O (n) в общем случае. Кроме того, вы все равно можете использовать LINQ для .Values ​​члена Словаря, если вам нужно. – Tommi

+0

Есть две перспективы в отношении того, чего вы хотите достичь. Я считаю, что мы оба дали вам несколько примеров, основанных на некоторых наших собственных предположениях. Мы использовали класс, чтобы иметь строго типизированный объект для работы. Он использует коллекцию словарей, я использую список. –

Смежные вопросы