foreach循环中的操作顺序

时间:2014-10-15 01:49:27

标签: c# loops foreach

我完全改变了我的制作工作台的工作方式,我遇到了一个问题。它现在的工作方式是显示工艺列表中的所有项目。如果您无法制作该项目,则表格中的项目纹理是半透明的。

我的问题是,当我检查项目是否可以制作时,我将bool变量CanCraft设置为true或false并且设置不正确。

 public void CheckForAvailableCrafts(Player player)
    {
        foreach (ItemRecipe recipe in CraftingList)
        {
            if (recipe.CheckForItemsNeeded(player) != null)
            {
                Output = recipe.Output;
                UpdateTable(Output);
            }
            else if (recipe.CheckForItemsNeeded(player) == null)
            {
                Output = new Item();
                Output.ItemName = "empty";
                UpdateTable(Output);
            }

CheckForItemsNeeded方法正常工作,因为它在重写此部分代码之前工作正常。如果我有一定数量的物品CanCraft项目是真的。问题在于UpdateTable方法。

            private void UpdateTable(Item output)
    {
        foreach (Item item in CraftingTableItems)
        {
            if (output.ItemName == item.ItemName)
            {
                item.CanCraft = true;
                if (output.ItemName == "empty")
                {
                    item.CanCraft = false;
                }
            }
        }
    }

我的CraftingTableItems是一个包含12个项目的列表,每个项目都设置为我的CraftingList中的配方。所以我在CraftingTable中有6个非空的项目。

在我制作完项目后,表格中的项目应该返回false值,但事实并非如此。我的for循环中的操作顺序是否正确?

2 个答案:

答案 0 :(得分:2)

我怀疑问题是Output变量。它没有被定义为方法的一部分,因此可以通过另一个线程的其他代码进行修改。您可以更改代码以使该变量本地化为方法(一般经验法则:始终使用变量可能的最小范围)或甚至完全消除它,但我会重写这样的全部内容:

public void CheckForAvailableCrafts(Player player)
{
    //names of items the player can craft
    var names = CraftingList.Where(r => r.CheckForItemsNeeded(player) != null)
                            .Select(r => r.Output.ItemName);

    //Item objects that player can craft
    var items = CraftingTableItems.Join(names, i => i.ItemName, n => n, (i, n) => i);

    //Set all to false (base state)
    foreach (var item in CraftingTableItems) {item.CanCraft = false;}
    //Set items player can craft back to true
    foreach(var item in items) {item.CanCraft = true;}
}

不仅代码更少,而且 更高效,因为先前代码必须检查玩家可以制作的每个可能项目的每个CraftingList条目... O(n < sup> 2 ),虽然这是(我认为)O(n Log n),甚至可能接近O(n)。

是的,.Join()调用看起来像希腊语,如果你不习惯lambda表达式,但它真的不那么难,而且:它会极大地简化和加速你的代码。如果您有一个EqualityComparer类,根据名称比较两个项目,或者Item类型实现IEquatable来比较ItemNames,您可以进一步简化这一点(您可能会发现它很有用)无论如何)。假设后者,Item正确实现IEquatable,您的代码将如下所示:

public void CheckForAvailableCrafts(Player player)
{
    //items the player can craft
    var craftableItems = CraftingList.Where(r => r.CheckForItemsNeeded(player) != null)
                                     .Select(r => r.Output);

    //Items objects from the CraftingTable that the player can craft
    craftableItems = CraftingTableItems.Intersect(craftableItems);

    //Set all to false (base state)
    foreach (var item in CraftingTableItems) {item.CanCraft = false;}
    //Set items player can craft back to true
    foreach(var item in craftableItems) {item.CanCraft = true;}
}

如果您不能首先发现差异,则第一个语句会在Select投影中保存一个步骤,第二个语句会从丑陋的Join()函数更改为更易于阅读的{{ 1}}

答案 1 :(得分:0)

在黑暗中拍摄,但我会做以下检查以防有人命名略有不同:

output.ItemName.ToLower() == item.ItemName.ToLower()