Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice
  2. We've opened up a space to discuss, share feedback, and showcase everything related to the Unity Shader Graph! Come show us what you've made.
    Dismiss Notice

Detecting change in a list

Discussion in 'Scripting' started by TheNuttyGamer, Feb 10, 2019.

  1. TheNuttyGamer

    TheNuttyGamer

    Joined:
    Oct 15, 2017
    Posts:
    3
    Hello, this is something I've been struggling with for a while. In my game, a UI Element should be updating every time its corresponding list gets updated. I've tried getters and setters but they just straight up don't work.

    Code (CSharp):
    1. public List<CrewMember> Crew
    2.     {
    3.         get { return crew; }
    4.         set { crew = value; UpdateCrewUI();}
    5.     }
    I am directly interacting with the 'Crew' list and elements do get added/ removed successfuly however the method just does not get called. I've tried putting in print statements as well to test it and those don't get executed either.

    From my research it appears that getters and setters don't actually work with lists in which case I would need a workaround, I haven't been able to find any however, any advice is appreciated.
     
  2. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    1,392
    Simplest solution is to encapsulate the actual list (make it private / protected). If you need it to be serialized for inspector - use [SerializeField] attribute on it. Alternatively, if you don't, mark it as readonly.
    Code (CSharp):
    1. [SerializeField] private List<CrewMember> _members = new List<CrewMember>();
    2. // Or
    3. private readonly List<CrewMember> _members = new List<CrewMember>();
    Then add a AddCrewMember() / RemoveCrewMember() methods to the class, alter list in there, call your method UpdateCrewUI in there as well.

    In C# it's best to not allow external objects to modify internal collections directly, unless you want that by design.
    (Avoid public modifiers on fields)
     
    Last edited: Feb 10, 2019
    Kiwasi and TheNuttyGamer like this.
  3. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    782
  4. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    2,999
    I have this piece of code I use, maybe it's useful, maybe it's not, it's up to you (under construction, so things will change as I go forward and optimize things, I more likely will make the list public to speed up the reads and those kind of things):
    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. namespace LurkingNinja.KujiKiri.Sets
    6. {
    7.     [Serializable]
    8.     public class AbstractSet<T> : ScriptableObject
    9.     {
    10.         public event Action<T> OnAddElement = delegate { };
    11.         public event Action<T> OnRemoveElement = delegate { };
    12.         public event Action<T> OnChangeElement = delegate { };
    13.         public event Action OnClear = delegate { };
    14.  
    15.         [SerializeField]
    16.         private List<T> Items = new List<T>();
    17.  
    18.         public int Count => Items.Count;
    19.  
    20.         public bool HasItems => Items.Count > 0;
    21.  
    22.         public bool Contains(T value) => Items.Contains(value);
    23.  
    24.         public T this[int index]
    25.         {
    26.             get => Items[index];
    27.             set
    28.             {
    29.                 Items[index] = value;
    30.                 OnChangeElement?.Invoke(value);
    31.             }
    32.         }
    33.  
    34.         public void Add(T item)
    35.         {
    36.             if(Items.Contains(item))
    37.                 return;
    38.             Items.Add(item);
    39.             OnAddElement?.Invoke(item);
    40.         }
    41.  
    42.         public void Remove(T item)
    43.         {
    44.             if(!Items.Contains(item))
    45.                 return;
    46.             Items.Remove(item);
    47.             OnRemoveElement?.Invoke(item);
    48.         }
    49.  
    50.         public void Clear()
    51.         {
    52.             if(!HasItems)
    53.                 return;
    54.             Items.Clear();
    55.             OnClear?.Invoke();
    56.         }
    57.  
    58.         public static bool IsNullOrEmpty(AbstractSet<T> set)
    59.         {
    60.             return set == null || !set.HasItems;
    61.         }
    62.     }
    63. }
    64.  
    It is part of a bigger framework I'm working on (to support future projects as well), this is, among other things, for support tag replacements. You can build any Sets (eg: GameObjectSet : AbstractSet<GameObject>) and then search (will be implemented and optimized later, depends on the use cases I'll have) or check if an element is in the Set or so on.