Unity Validate Assignments

I’ve found that, when iterating on a new feature or game object setup in Unity, my memory is my worst enemy. Specifically, I’ll frequently find that I’ve either completely forgot to set up references to fields in my scripts or prefabs in the editor. This will cause runtime errors like null reference exceptions, selecting from empty lists, or just unexpected behavior.

To combat this, I started to write something along the lines up the following:

 1public GameObject someReference;
 2
 3private void Awake()
 4{
 5    if (someReference == null) 
 6    {
 7        Debug.Log($"{nameof(someReference)} not found.");
 8    }
 9    // Rest of initialization code
10}

Which will, on object initialization, print out fields that I’ve failed to assignin the inspector, making this class of bug really easy to identify. However, for scripts with a large quantity of inspector-assigned fields, this gets cumbersome very quickly. It also adds a ton of boilerplate to the Awake/Start methods. There has to be something better.

And there is! Introducing: the ValidateAssignment attribute

1[ValidateAssignment]
2public GameObject someReference;
3
4private void Awake()
5{
6    this.ValidateAssignments();
7    // Rest of initialization code
8}

This moves the validation logic to the moment when you define a field that should be validated - simply slap a [ValidateAssignment] attribute on the field, and remember to call this.ValidateAssignments() in either Start or Awake, depending on preference. While the approach uses reflection, it’s only enabled while in-editor, the validation logic is turned off for release builds.

Full code:

 1namespace Core.Attributes
 2{
 3    using System;
 4    using System.Collections;
 5    using System.Collections.Generic;
 6    using System.Linq;
 7    using System.Reflection;
 8
 9    [AttributeUsage(AttributeTargets.Field)]
10    public sealed class ValidateAssignmentAttribute : Attribute
11    {
12    }
13
14    public static class ValidateAssignmentExtensions
15    {
16        public static void ValidateAssignments(this UnityEngine.Object o)
17        {
18#if UNITY_EDITOR
19            IEnumerable<FieldInfo> properties = o.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
20                .Where(prop => Attribute.IsDefined(prop, typeof(ValidateAssignmentAttribute)));
21
22            foreach (FieldInfo field in properties)
23            {
24                object fieldValue = field.GetValue(o);
25
26                bool logNotAssigned = fieldValue switch
27                {
28                    IList list => list.Count <= 0,
29                    ICollection collection => collection.Count <= 0,
30                    UnityEngine.Object unityObject => !unityObject,
31                    _ => fieldValue == null
32                };
33
34                if (logNotAssigned)
35                {
36                    Debug.Log($"{field.Name} not found.");
37                }
38            }
39#endif
40        }
41    }
42}

Also available as a Gisthub snippet .


Privacy Policy