Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Question Unique List items share the same reference?

Discussion in 'Editor & General Support' started by Doomchecker, Oct 24, 2023.

  1. Doomchecker

    Doomchecker

    Joined:
    Apr 5, 2021
    Posts:
    111
    I have this List:

    Code (CSharp):
    1. public List<WallClass> wallClasses = new();
    2.  
    3. [Serializable]
    4. public class WallClass
    5. {
    6.     public WallDirectionEnum direction = WallDirectionEnum.Right;
    7.     public int length = 4;
    8.  }
    And this list is within an item of another List:
    Code (CSharp):
    1. [SerializeReference] public List<LevelBase> levels = new();

    So the wallClasses list is within the items of the levels list.
    My problem is, when I have multiple items of the same type in the levels list, the wallClasses are not unique but shared among all the items in the levels list.

    For example when I have two items in the levels list, each with one item in the wallClasses list and I change the length in one item, the other item gets the same values (its a direct reference).

    I don't understand why and how I can avoid this.

    Thanks for any ideas!
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    7,024
    Your WallClass is a reference type (class), like GameObject. Therefore if you instantiate the class, and assign it to a dozen fields and add it to lists and what not, every reference points to the same instance.

    If you don't want this, you have to make WallClass a value type (struct), like Vector3. This means every assignment (including adding to collections) will store a copy of the values rather than the instance itself, making each unique.
     
  3. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,704
    Or you could just make a unique instance of List<WallClass> for each entry in levels.
     
    spiney199 likes this.
  4. Doomchecker

    Doomchecker

    Joined:
    Apr 5, 2021
    Posts:
    111
    I failed to mention something important (sorry). I use a custom property drawer (UI Toolkit) for the list.

    Anyways, I found the solution.

    First to the problem:
    When drawing a ListView inside a ListView in a custom property drawer, in the ListView.MakeItem and ListView.BindItem functions, the relationship to the outer list is lost. These functions will always use last item of the outer list as the current item.

    To resolve this, one has to pass in the SerializedObject into the bindItem function and then update the list property with it:
    Code (CSharp):
    1.         private void WallClassesBindItem(VisualElement item, int index, SerializedProperty property)
    2.         {
    3.            
    4.             wallClassesProperty = property.FindPropertyRelative(nameof(LevelWalls.wallClasses));
     
    Last edited: Oct 25, 2023