Conditional Compilation

Conditional Compilation allows parts of a script to be selectively removed by the compiler when specific compilation symbols are defined or not. For example:

Regular if Conditional #if
public void MyMethod(bool condition)
{
    if (condition)
    {
        Debug.Log("Condition is true");
    }
    else
    {
        Debug.Log("Condition is false");
    }
}
public void MyMethod()
{
#if UNITY_EDITOR
    Debug.Log("This is the Unity Editor");
#else
    Debug.Log("This is a Runtime Build");
#endif
}
This condition could be either true or false when MyMethod is called so it needs to be checked every time. The #if is checked when the code is compiled. In the Unity Editor the UNITY_EDITOR symbol is defined so the code is just public void MyMethod() { Debug.Log("This is the Unity Editor"); } and in Runtime Builds that symbol is not defined so the code is just public void MyMethod() { Debug.Log("This is a Runtime Build"); }. This is known as Platform Dependent Compilation.

Anything marked as [Editor-Only] (such as the Animancer.Editor.AnimancerEditorUtilities class) will only exist when the UNITY_EDITOR symbol is defined (i.e. in the Unity Editor) so any usage will need to be inside a #if UNITY_EDITOR and #endif block.

The UNITY_ASSERTIONS symbol is similar, but it is also defined in Runtime Builds if the Development Build toggle is enabled in the Build Settings. This is referred to as [Assert-Only] and is useful for performing additional safety checks and debug logging without affecting the performance of Runtime Builds at all.

Attribute

The [System.Diagnostics.Conditional] can be placed on methods so that any calls to them are removed by the compiler unless the specified symbol is defined. For example:

// You could put this in a common utility class.
[System.Diagnostics.Conditional("UNITY_EDITOR")]
public static void EditorLog(object message)
{
    Debug.Log(message);
}

public void MyMethod()
{
    EditorLog("This is a test");
}
  • In the Unity Editor, calling MyMethod would log "This is a test" in the Console.
  • In a Runtime Build, calling MyMethod would do nothing as if you had put #if UNITY_EDITOR and #endif around the EditorLog call.

Any method marked as [Editor-Conditional] or [Assert-Conditional] is using a [Conditional] attribute.

Assertions

An assertion, or Assert statement, tests a condition:

  • If the condition evaluates to true, no action occurs.
  • If the condition evaluates to false, the assertion fails.

It's like saying "(condition) must be true, so give error (message) if it is not".

The consequences of an assertion failing depend on the specific method used:

  • Debug.Assert logs an error in the Console but will keep executing the rest of the method.
  • AnimancerUtilities.Assert throws an Exception (UnityEngine.Assertions.AssertionException) to prevent the rest of the method from executing.

Both methods have a [System.Diagnostics.Conditional("UNITY_ASSERTIONS")] attribute so they will only be executed in the Unity Editor and in Development Builds, but not in regular release builds.

For example:

var rigidbody = GetComponent<Rigidbody>();
Debug.Assert(rigidbody != null, "There is no Rigidbody attached to this object.");
// ... Use the rigidbody.
  • If there is a Rigidbody component attached to that object, the assertion will pass and do nothing.
  • But otherwise it will log the specified error message.