NullReferenceException when I tried to get the values of a Dictionary using LINQ

I don’t have any problem when I tried to get the keys, but I was having a problem when I tried to get the value from a Dictionary. The values is a class that contains 2 fields with a constructor with 2 parameters. Here is the code :

    public class SetupWeapon {

        public int poolSize;
        public GameObject prefab;

        public SetupWeapon(int size, GameObject goPrefab) {
            this.poolSize = size;
            this.prefab = goPrefab;
        }
    }
    private SetupWeapon[] _setupWeapon = new SetupWeapon[1];
    private Dictionary<int, SetupWeapon> _weaponData = new Dictionary<int, SetupWeapon>();
    public int[] AttackIDs {
        get {
            var toArray = _weaponData.Select(a => a.Key).ToArray();
            return toArray;
        }
    }
    private int[] PoolSize {
        get {
            var toArray = _weaponData.Select(a => a.Value.poolSize).ToArray();
            return toArray;
        }
    }
    private GameObject[] Prefab {
        get {
            var toArray = _weaponData.Select(a => a.Value.prefab).ToArray();
            return toArray;
        }
    }

    void Start () {
        CollectData(setPhysical); // collecting data
        CollectData(setLeftEye);
        CollectData(setRightEye);
        CollectData(setForehead);
        CollectData(setMouth);
        for (int i = 0; i < AttackIDs.Length; i++){
            Debug.Log(AttackIDs[i]); // works just fine
            Debug.Log(_weaponData[0].poolSize); // works just fine
            Debug.Log(_weaponData[0].prefab.name); // works just fine
            Debug.Log(PoolSize[0]); // NullReferenceException
            Debug.Log(Prefab[0].name); // NullReferenceException
        }
    }

When you look at the Debug codes, this Debug.Log(_weaponData[0].poolSize) works just fine while this Debug.Log(PoolSize[0]); got NullReferenceException.
Did I miss something important that cause this error ?

If I understand your code, you are using Linq to “flatten” the dictionary into a pair of arrays for accessing the two inner class elements (int and GameObject) as individual linear arrays.

For the error above to happen, it appears you would have to have added at least one key to the dictionary that has a null SetupWeapon() object.

Let’s break this down: When you say _weaponData[0] you are getting the Dictionary entry for the key == 0

When you say PoolSize[0] you are getting the first element in your freshly-fabricated array. This is not necessarily the same as the dictionary entry for key == 0.

Not only that, if ANY of your Dictionary entries are null, then it won’t matter which one you are accessing: inside of your getter, Linq will access the null entry, dereference the .size field during the Select() statement’s predicate, and throw the null reference exception.

So I bet if you put a breakpoint in your getter and inspected the dictionary contents, you’d find one of your keys is mapped to null.

I notice that the field _setupWeapon is set to an array of one element, but that element is null. Not sure if someone else is using that to add a null entry to you dictionary, but it obviously isn’t referred to anywhere in the above code.

Finally, this isn’t a great way to approach this problem because every time you access your arrays, it is producing again and again that reordering of the data. It’s fine for fiddling around but I’d not recommend using it in production code, and certainly not on mobile. Linq is a pretty bad idea all around for mobile platform use, for its memory thrashing, which you are exacerbating by this constant re-creation of the arrays.

Thanks and yes you are right. When I checked back inside the dictionary in values part, I found a null value. That’s because I have a multipurpose method called CollectData that sometimes I need a null value. So I resolved it by overloading the CollectData method to avoid this error.
And thanks again for telling me that using Linq is a bad idea for mobile platform. This project is a mobile game.

1 Like

If you’re just using this to keep track of a batch of object pools, there is nothing wrong with using a simple array of them and then iterating linearly when you are consuming them. I’m not 100% what your needs are here, but there are lots of web-available examples of object pooling systems out there with various interfaces… perhaps one can meet your needs.

1 Like