Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

[SOLVED] List.Exists / List.Any return NRE when List doesn't has object

Discussion in 'Scripting' started by zurisar, Feb 6, 2020.

  1. zurisar

    zurisar

    Joined:
    Nov 4, 2019
    Posts:
    24
    Hello guys, I meet another problem.
    I has 3 lists with items: factoryItems, productionItems, supplierItems
    When player click on item script should check all 3 lists and find needed item.
    My items are scriptable object, and I use itemID variable setted by hand

    When player click on item he call Use() functions, here it is
    Code (CSharp):
    1. public override void Use()
    2.     {
    3.         base.Use();
    4.  
    5.         Debug.Log("ItemID: " + itemID);
    6.  
    7.        Item item = Inventory.instance.GetItemByID(itemID);
    8.        if (item)
    9.         {
    10.             if(Inventory.instance.CheckItem(item))
    11.             {
    12.                 Debug.Log("Item is here");
    13.             }
    14.             Debug.Log("You have this item " + itemTitle);
    15.             Debug.Log("Items need for craft " + prodList.Count);
    16.             int resourceQty = prodList.Count;
    17.             int resQty = 0;
    18.             foreach(Item res in prodList)
    19.             {
    20.                 if(Inventory.instance.CheckItem(res))
    21.                 {
    22.                     resQty += 1;
    23.                 }
    24.             }
    25.  
    26.             if(resQty == resourceQty)
    27.             {
    28.                 Debug.Log("Succes, you can craft " + itemTitle);
    29.                 int value = craftMultiplier;
    30.                 Inventory.instance.AddItem(item, value);
    31.                 foreach(Item res in prodList)
    32.                 {
    33.                     Inventory.instance.RemoveItem(res, 1);
    34.                 }
    35.             }
    36.             else { Debug.Log("You don't have enough resource"); }
    37.         }
    38.        else
    39.         {
    40.             Debug.Log("You haven't " + itemTitle);
    41.         }
    42.     }
    In this string
    Item item = Inventory.instance.GetItemByID(itemID);
    script call Inventory function, take itemID and give me object.

    GetItemByID(itemID) firstly try to find item in player inventory, if yes just add item amount, if no add item to iventory
    Code (CSharp):
    1. public Item GetItemByID(int itemID)
    2.     {
    3.         Debug.Log("GetItemByID called, itemID: " + itemID);
    4.         if (CheckItemByID(itemID))
    5.         {
    6.             return factoryItems.Find(x => x.itemID == itemID);
    7.         }
    8.         else
    9.         {
    10.             return CheckItemType(null, itemID);
    11.         }
    12.     }
    As you can see firstly I check item if it exists. I this part it the problem, I got NRE here:
    Code (CSharp):
    1. public bool CheckItemByID(int itemID)
    2.     {
    3.         Debug.Log("Try to check item by ID " + itemID);
    4.         return factoryItems.Any(x => x.itemID == itemID);
    5.     }
    I tried to use .Exists and .Any, but both methods crash with NRE.

    How I should check List for object if I know only object variable and don't have object itself?
     
  2. Ardenian

    Ardenian

    Joined:
    Dec 7, 2016
    Posts:
    313
    If you get NRE in this particular code section, it means that either the
    factoryItems
    list is null or any element in it, as you try to access a property of an object that does not exist.

    Try this, although this is probably not fixing the underlying problem of something being null.

    return factoryItems.Any(x => x != null && x.itemID == itemID);


    As a little tip, you can improve this code. Right now, you go through the list of factoryItems to check if an item has the ID, then if it is true, then you go through the list again to return it. Try to do it like this:

    Code (CSharp):
    1.     public bool CheckID(int itemID){
    2.     return factoryItems.Find(x => x != null && x.itemID == itemID);
    3.     }
    4.  
    Code (CSharp):
    1.     public Item GetItemByID(int itemID)
    2.         {
    3.             Debug.Log("GetItemByID called, itemID: " + itemID);
    4.             Item item = CheckItemByID(itemID);
    5.             if (item != null)
    6.             {
    7.                 return item;
    8.             }
    9.             else
    10.             {
    11.                 return CheckItemType(item, itemID);
    12.             }
    13.         }
    14.  
    There are also other solutions using the out parameter modifier, with a popular example being Int32.TryParse.
     
    GileanVoid likes this.
  3. zurisar

    zurisar

    Joined:
    Nov 4, 2019
    Posts:
    24
    Greate thanks man! It works, and I need null if element doesn't exist. Because factoryItems work like player inventory and if player hasn't item, I get it from another list, get as object and add to factoryItems.

    I understand that you advice me, I'll improve my code for lesser queries to lists, actually for now I can don't do List.Exists and always use List.Find.