Best practice for required references

Hi,

I write a lot of scripts like this:

public class MyScript : MonoBehaviour
{
    public Transform VeryImportantReference;

    private void Start()
    {
        if (VeryImportantReference == null)
        {
            Debug.LogError("VeryImportantReference not set.");
            enabled = false // avoid log spam
        }
       
    }
   
    private void Update()
    {
        // use the reference here...
    }
}

Is there a best practice of this scenario or even a RequireField attribute like RequireComponent. This checks are very repetitive and annoying…

No, there isn’t one.

You can make one.

Easiest way is to just write an ‘assert’ function:

public static class Assert
{

    public static bool ReferenceExists(UnityEngine.Object obj, string name)
    {
        if(obj == null)
        {
            Debug.LogError(name + " not set");
            return false;
        }
        else
        {
            return true;
        }
    }

}

public class MyScript : MonoBehaviour
{

    public Transform VeryImportantReference;

    void Start()
    {
        this.enabled = Assert.ReferenceExists(VeryImportantReference, "VeryImportantReference");
    }

}

Unity has its own Assert class so you don’t even have to write your own :slight_smile:

1 Like

Nice, is that new?

New in 5 I think. Not sure which minor version.

Nice, that goes in the right direction. Maybe I can create something, that gives a visual feedback in the editor, like a (Property xyz not set warning)… A attribute or something like that.

You can also do that in the OnValidate MonoBehaviour message to make sure your references are assigned at edit time instead of doing in Start.

I’ve created a simple attribute and property drawer:

Attribute:

public class RequiredAttribute : PropertyAttribute
{
}

Drawer:

[CustomPropertyDrawer(typeof(RequiredAttribute))]
public class RequiredDrawer : PropertyDrawer
{
    private const float HELPBOX_HEIGHT = 38.0f;
    private const float TOP_MARGIN = 2.0f;

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        float propHeight = EditorGUI.GetPropertyHeight(property, label);
        position.height = propHeight;

        EditorGUI.PropertyField(position, property, label);

        if (property.objectReferenceValue == null)
        {
            position.y += position.height + TOP_MARGIN;
            position.height = HELPBOX_HEIGHT;
            EditorGUI.HelpBox(position, string.Format("{0} is required!", label.text), MessageType.Error);
        }
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        float height = EditorGUI.GetPropertyHeight(property, label);
        if (property.objectReferenceValue == null)
        {
            height += HELPBOX_HEIGHT + TOP_MARGIN;
        }

        return height;
    }
}

Now, you will get an error in the inspector, if the property with the require attribute has a null reference.
This isn’t perfect because if you collapse the component, there will be no reminder, that you have to set this property before you should press play.

2 Likes