簡體   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