【问题标题】:c# how to retrive objects as values from arrayc#如何从数组中检索对象作为值
【发布时间】:2013-05-13 08:24:33
【问题描述】:

我正在尝试创建一个简单的“库存”系统来存储项目,其中键是项目名称,其余信息存储为值。但是,我很难弄清楚如何阅读这些信息。例如,如果我说一个包含 10 个项目的列表,并且我想从下面概述的关键“电视”中选择项目“类型”信息,我该怎么做?

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

【问题讨论】:

  • 您有什么理由仍在使用非泛型Hashtable 集合而不是Dictionary<,>? (听起来您应该创建一个 Item 类来封装所有这些值。)
  • 没用过HashTable,但是使用自定义实体类有什么顾虑吗?
  • 我对 C# 及其数组类型相当陌生。如果有更好的方法,如果有人能介绍给我,我将不胜感激。
  • 你熟悉OOP吗?为您的项目定义类并使用通用 Dictionary 创建结构良好且足够快的数据实体。

标签: c# arrays object


【解决方案1】:

创建一个item类来封装属性:

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

【讨论】:

  • 您忘记输入您的库存。添加
  • 只是好奇 - 在你的班级中使用字段对抗自动属性有什么好处吗?
  • @Tommi:这取决于它的用途。您可以随时对其进行重构。
  • 尝试这种方法我得到一个错误 - 错误 CS1525: Unexpected symbol [', expecting identifier'
  • 这是因为我上面提到的错字。索引器不应以逗号分隔,请将inventory.["television"] 替换为inventory["television"]
【解决方案2】:

我建议您考虑库存清单中某一类型的不止一件物品的可能性,即两台或多台电视机,而不是只有一台。

使用基类和派生类:

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&lt;InventoryItem&gt; 来存储集合:

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&lt;string, InventoryItem&gt;string 键是唯一的库存项目标识符。它会更快。

【讨论】:

  • 我能解释一下这种方法和@ChrisWue 之间的区别吗?
  • 主要区别是使用列表而不是字典。如果您想通过密钥获取项目,我认为这不是一个好主意。字典查找复杂度为 O(1),而 LINQ 查询通常为 O(n)。此外,如果需要,您仍然可以在 Dictionary 的 .Values 成员上使用 LINQ。
  • 对于您想要实现的目标有两种观点。我相信我们俩都根据我们自己的一些假设给了你一些例子。我们都使用了一个类来使用强类型对象。他使用字典集合,我使用列表。
猜你喜欢
  • 2020-08-22
  • 2013-06-22
  • 2018-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-25
相关资源
最近更新 更多