Reflecting on abstract data structures

I am attempting to create a class that will be able to find all objects in a scene, get all of their members, and then return what of those members is null (so that we can go through by hand, and figure out if they need to be assigned to by hand, or not.

(this class shall not be included in the release due to performance)

I have gotten the find all objects in a scene, and get all their Fields (using a combination of LINQ, and reflection), but in our project we are using quite a bit of Arrays/Lists/Dictionaries work, and it will show me that these are structures are there, but I can’t figure out how to get to the items being held in the arrays, or sudo arrays.

is there a way with reflection (while having the FieldInfo pointing at the data structures, and the MonoBehavior) to get at the items the data structure holds?

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

public class SceneDebugging : MonoBehaviour {
	[SerializeField]
	public List<MonoBehaviour> list;
	
	public void CheckScene(){
		var _list = (GameObject.FindObjectsOfType(typeof(GameObject)) as GameObject[])
			.SelectMany( go => go.GetComponents<MonoBehaviour>())
				.OrderBy(thing => { return thing.name; })
				.ToList();

		list = _list;
		
		if(list != null && list.Count > 0){
			string str = "";
			foreach(MonoBehaviour behave in list){
				str += behave.name + behave.transform.position.ToString() + " component: " + behave.GetType().Name + "

“;
List _newList = behave.GetType().GetFields().ToList();
if(_newList != null && _newList.Count > 0){
foreach(FieldInfo info in _newList){
if(info.FieldType.ToString().Contains(”.List")){
str += " " + info.Name;
str += “.typeof(” + info.FieldType + "): ";
str += ((info.GetValue(behave)!=null)?info.GetValue(behave):“null”);
str += "
";
var _listList = info.GetValue(behave).GetType().GetFields().ToList();
if(_listList != null && _listList.Count > 0){
for(int ii = 0; ii< _listList.Count; ii++){
str += " " + _listList[ii].Name;
str += “.typeof(” + _listList[ii].FieldType + "): ";
str += ((_listList[ii].GetValue(behave)!=null)?_listList[ii].GetValue(behave):“null”);
str += "
";
}
}else{Debug.Log(“list is empty, or null”);}
}else if(info.FieldType.ToString().Contains(“String”)){
str += " " + info.Name;
str += “.typeof(” + info.FieldType + “): “;
str += ((info.GetValue(behave)!=null)?”"” + info.GetValue(behave) + “"”:“null”);
str += "
";
}else{
str += " " + info.Name;
str += “.typeof(” + info.FieldType + "): " ;
str += ((info.GetValue(behave)!=null)?info.GetValue(behave):“null”);
str += "
";
}
}
}
}
Debug.Log(str);
}
}
}

this is what I currently have. the issue that I am running into is that the else statement (line 39) always fires, and I cannot get the elements out of the data Generic.Collections data structure

Hello,

I assume you’re writing something that checks whether there are any unassigned inspector values, so I’ll only go over checking for nulls in Built-in arrays and not Generic Lists etc. But you should be able to implement the use of those yourself if you really do need them.

TBO I don’t understand why you need Linq, I just wrote the same thing without the need to include Linq at all, but besides that you should take note that null is not a bad value. I have written many a code that relies on null values to work and there is nothing wrong with that. Sometimes even nulls are necessary :slight_smile:

Also note that not all values will show up for the null check depending on how the inspectors of certain Components are set up. For instance this null checker will miss the render texture of the Camera component, since it is not technically a field but a property. You might want to include those :wink:

#pragma strict

import System;
import System.Reflection;

static class NullValueChecker {
    //check the entire scene for null values
    function Check() {
        //Get all objects
        var objects:Object[] = UnityEngine.Object.FindObjectsOfType(typeof(Component));
        
        //check for null values
        for (var object:Object in objects) {
            CheckObject(object);
        }
    }
    
    //check for a single object
    private function CheckObject(object:Object) {
        //Get field infos for all pubic and instance (default) fields
        var fields:FieldInfo[] = object.GetType().GetFields();
        
        //Iterate through all fields
        for (var field:FieldInfo in fields) {
            //Only serialized fields are checked (Show up in editor)
            if (!(field.Attributes & FieldAttributes.NotSerialized)) {
                //check each field for null value/s
                CheckNull(field.FieldType, field.GetValue(object));
            }
        }
    }
    
    //check for a single field
    private function CheckNull(type:Type, value:Object) {
        if (value == null) {
            //Handle null values here
            //I just decided to print out when It found one
            Debug.Log("Null Value Found");
        }
        else {
            //non null values
            if (type.IsArray) {
                //if our type is an array we can just go through it and check for each object
                type = type.GetElementType();
                for (var obj:Object in value) {
                    CheckNull(type, obj);
                }
            }
        }
    }
}

Everything should be explained in the comments, but feel free to ask further questions. (Yes I did just implement the entire thing instead of just the arrays part)

Hope this helps,
Benproductions1