繁体   English   中英

foreach循环中的操作顺序

[英]Order of operations in a foreach loop

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

我的问题是,当我检查商品是否可以制作时,我将布尔变量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为true。 问题出在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个不为空的项目。

在制作完项目后,表中的项目应返回一个假值,但不是。 for循环中的操作顺序是否正确?

我怀疑问题是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 2),而这是(我认为)O (n Log n),甚至可能接近O(n)。

是的,如果您不习惯使用lambda表达式,那么.Join()调用看起来就像是希腊文,但实际上并没有那么困难,而且一遍又一遍:它极大地简化了代码并加快了速度。 如果您有一个EqualityComparer类,可以根据名称比较两个项目,或者您的Item类型实现IEquatable以便在IEquatable进行比较,则可以进一步简化此操作(无论如何您都可以发现它很有用)。 假设后者,在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()函数更改为易于阅读的Intersect()

这里是在黑暗中拍摄,但如果有人命名略有不同,我将做以下检查:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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