I find myself doing null-checks for a lot of inspector fields, which have to be set by the designer in the editor:
public class Test : MonoBehaviour
{
[SerializeField]
private GameObject m_SomeObject;
void Awake ()
{
if(m_SomeObject == null)
{
Debug.LogError(name + ": Is missing component reference to: " + typeof(GameObject).Name, this);
this.enabled = false;
return;
}
}
}
I was wondering if I could somehow automate this process with say, something like an attribute or an extension method. Is there any approach that lets me define a generic/flexible error message, which can be applied to variables as an attribute or via a one-line in awake to do the same thing?
Thanks for any ideas!
You could write a script that inspects the behaviours via reflection and then checks the state of all of the properties - but that might be a little overkill.
Yea, probably too much, even if I only use it during development. Might be an option for an editor tools, that tests all gameobjects for missing references, but then it would be hard to sort out which ones actually require the reference to be set and which are optional.
Still hoping for some genius solution via extension or attribute. ^^
You could definitely write an extension method but you’re still stuck writing a little code.
Something like this:
public static class Extensions
{
public static void Validate(this MonoBehaviour monoBehaviour, object target)
{
if(target == null)
{
Debug.LogError(name + ": Missing component reference to: " + typeof(target).Name, this);
this.enabled = false;
return;
}
}
}
Then your validation check becomes:
public class Test : MonoBehaviour
{
[SerializeField]
private GameObject m_SomeObject;
void Awake ()
{
Validate(m_SomeObject);
}
}
Note: I wrote this right here so it’s untested, syntax might be a little off.
2 Likes
To relieve this requirement from each component, I think reflection is actually the lightest weight solution out there in terms of upfront development. I assume this is a development only feature anyways, since it seems odd to disable GameObjects once the game is released.
Just one error I spotted in @GroZZleR 's code.
public static class Extensions
{
public static void Validate(this MonoBehaviour monoBehaviour, object target)
{
if(target == null)
{
// can't call typeof() on an object -- need to use GetType()
Debug.LogError(name + ": Missing component reference to: " + target.GetType().Name, this);
this.enabled = false;
return;
}
}
}
Actually, I see no reason to disable your GameObject, so why bother with an extension method? For null checking I often use assertions like:
public class Test : MonoBehaviour
{
[SerializeField]
private GameObject m_SomeObject;
void Awake ()
{
Assert.NotNull(m_SomeObject, string.Format("{0}: Is missing component reference to: {1}", name, m_SomeObject.GetType().Name));
}
}
You would need to make an Assert class but it would just have some static methods which throw Exceptions when their test fails.
2 Likes
Thank you both, I like those approaches! I went with the extension method, because it’s easy to pass the MonoBehaviour as context to Debug.LogError, which allows for a ping/highlight in the hierarchy when clicking the error message.
public static void ValidateInspectorField(this MonoBehaviour monoBehaviour, Object target)
{
if(target == null)
{
Debug.LogError(monoBehaviour.name + ": Is missing component reference to: " + target.GetType().Name, monoBehaviour);
}
}
It’s worth noting that checking System.object does not work correctly. It does return null, but for some reason the == check is not triggered correctly. Instead, I’m using UnityEngine.Object which works.
It might have to do with this: Unity Blog
The == operator apparently is implemented in a special way in Unity.
public Transform someTransform;
void Awake ()
{
this.ValidateInspectorField(someTransform);
}
1 Like