-
Notifications
You must be signed in to change notification settings - Fork 11
Features Inspector Inspector Validation Attributes
Protect your data with declarative validation and read-only presentation.
Unity Helpers provides validation attributes that help maintain data integrity and prevent accidental modifications. These attributes work with the Unity inspector and can validate fields at runtime.
Displays a field in the inspector as read-only, preventing accidental modifications while keeping the value visible.
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class GameManagerReadOnly : MonoBehaviour
{
[WReadOnly]
public string sessionId = "abc-123-xyz";
[WReadOnly]
public float elapsedTime = 0f;
[WReadOnly]
[SerializeField]
private int internalScore = 100;
}Behavior:
- Field appears grayed out in the inspector
- Value is visible but cannot be edited through the inspector
- Useful for displaying computed values, debug info, or auto-generated IDs
- Works with any serializable field type
Visual Reference
Fields marked with [WReadOnly] appear grayed out and cannot be edited
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class EntityReadOnly : MonoBehaviour
{
// Auto-generated unique identifier
[WReadOnly]
public string entityId = System.Guid.NewGuid().ToString();
// Computed property exposed for debugging
[WReadOnly]
[SerializeField]
private float _currentHealth;
// Reference that should only be set via code
[WReadOnly]
public Transform cachedTarget;
// Frame counter for debugging
[WReadOnly]
public int framesSinceLastUpdate;
}Why Use WReadOnly:
- Prevent accidents: Stop designers from accidentally modifying auto-generated values
- Debug visibility: Show internal state without allowing modification
- Documentation: Make it clear which fields are managed by code vs. configured in the editor
- Data integrity: Protect computed or cached values from manual overrides
Visual Reference
Multiple field types (string, float, Transform, int) displayed as read-only
Validates that a field is not null, providing both visual inspector feedback and runtime validation. When a field marked with [WNotNull] is null, the inspector displays a warning or error HelpBox. Additionally, calling CheckForNulls() on an object will throw an ArgumentNullException for any null [WNotNull] fields.
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class PlayerControllerNotNull : MonoBehaviour
{
[WNotNull]
public Rigidbody2D rb;
[WNotNull]
public SpriteRenderer spriteRenderer;
[WNotNull]
[SerializeField]
private AudioSource audioSource;
private void Awake()
{
// Validates all [WNotNull] fields are assigned
// Throws ArgumentNullException if any are null in Editor ONLY
this.CheckForNulls();
}
}Behavior:
- Inspector feedback: Displays a HelpBox warning (yellow) or error (red) when the field is null
-
Runtime validation: Call
this.CheckForNulls()to validate all[WNotNull]fields - Throws
ArgumentNullExceptionwith the field name if any marked field is null - Works with both Unity
Objecttypes and plain C# objects - All validation runs only in the Unity Editor (stripped in builds for performance)
Visual Reference
Fields marked with [WNotNull] display a HelpBox in the inspector when null
The WNotNullMessageType enum controls how null fields are displayed in the inspector:
| Value | Description |
|---|---|
Warning |
Displays a yellow warning HelpBox (default) |
Error |
Displays a red error HelpBox |
The [WNotNull] attribute supports multiple constructor overloads for flexibility:
// Default: warning message type with auto-generated message
[WNotNull]
public GameObject target;
// Inspector shows: "target must be assigned"// Error message type with auto-generated message
[WNotNull(WNotNullMessageType.Error)]
public AudioSource criticalAudioSource;
// Inspector shows red error: "criticalAudioSource must be assigned"// Warning with custom message
[WNotNull("Player needs a target to attack")]
public Transform attackTarget;
// Inspector shows yellow warning: "Player needs a target to attack"// Error with custom message
[WNotNull(WNotNullMessageType.Error, "Audio source is required for sound effects")]
public AudioSource audioSource;
// Inspector shows red error: "Audio source is required for sound effects"using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class EnemyAI : MonoBehaviour
{
// Yellow warning - nice to have
[WNotNull]
public ParticleSystem hitEffect;
// Red error - critical reference
[WNotNull(WNotNullMessageType.Error)]
public Transform patrolPath;
// Warning with helpful context
[WNotNull("Assign the player tag or the enemy won't detect the player")]
public string playerTag;
// Error with specific instructions
[WNotNull(WNotNullMessageType.Error, "Drag the NavMeshAgent component here - required for movement")]
public UnityEngine.AI.NavMeshAgent agent;
}Visual Reference
Warning (yellow) and Error (red) HelpBoxes for null fields in the inspector
The CheckForNulls() extension method validates all [WNotNull] fields at runtime:
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public sealed class EnemyManager : MonoBehaviour
{
public void RegisterEnemy(GameObject enemy) { }
}
public class EnemySpawner : MonoBehaviour
{
[WNotNull]
public GameObject enemyPrefab;
[WNotNull]
public Transform spawnPoint;
[WNotNull(WNotNullMessageType.Error)]
public EnemyManager enemyManager;
private void Start()
{
// If any [WNotNull] field is null, this throws with the field name
// Example: ArgumentNullException("enemyPrefab")
this.CheckForNulls();
// Safe to use - we know these are assigned
SpawnEnemy();
}
private void SpawnEnemy()
{
GameObject enemy = Instantiate(enemyPrefab, spawnPoint.position, Quaternion.identity);
enemyManager.RegisterEnemy(enemy);
}
}Both the inspector HelpBox display and the CheckForNulls() extension method are only active in the Unity Editor:
// The validation code only runs in UNITY_EDITOR
// In builds, CheckForNulls() does nothing (stripped for performance)
this.CheckForNulls();This means:
- Development: Visual feedback in inspector + runtime null checking with detailed exception messages
- Production: Zero runtime cost (all validation code is stripped)
public class UIManager : MonoBehaviour
{
// Required reference with error severity - validated at runtime
[WNotNull(WNotNullMessageType.Error)]
[SerializeField]
private Canvas mainCanvas;
// Optional reference - not validated
[SerializeField]
private AudioSource clickSound;
// Read-only and required
[WReadOnly]
[WNotNull]
public RectTransform cachedRect;
// Group with validation and custom message
[WGroup("UI Elements")]
[WNotNull("Start button required for main menu")]
public Button startButton; // In group
[WNotNull(WNotNullMessageType.Error, "Quit button required for main menu")]
[WGroupEnd("UI Elements")] // quitButton IS included, then closes
public Button quitButton; // In group (last field)
}Why Use WNotNull:
- Visual feedback: See missing references immediately in the inspector without running the game
- Severity control: Use warnings for nice-to-have references, errors for critical ones
- Custom messages: Provide helpful context about why a reference is needed
-
Early failure: Catch missing references at game start with
CheckForNulls(), not when first used - Clear errors: Get the exact field name in the exception message
- Documentation: Make required references explicit in code
- Zero runtime cost: All validation stripped from builds
Validates that a field is properly assigned, providing visual inspector feedback when validation fails. Unlike [WNotNull] which only checks for null references, [ValidateAssignment] validates that fields are "properly assigned" based on their type, including checking for empty strings, empty collections, and null references.
| Field Type | Validation Rule |
|---|---|
Unity Object references |
Not null |
| Strings | Not null or whitespace |
IList (arrays, List)
|
Has at least one element |
ICollection |
Has at least one element |
IEnumerable |
Has at least one element |
| Other types | Not null |
using System.Collections.Generic;
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class EnemySpawner : MonoBehaviour
{
[ValidateAssignment]
public GameObject enemyPrefab;
[ValidateAssignment]
public string enemyName;
[ValidateAssignment]
public List<Transform> spawnPoints;
private void Start()
{
// Logs warnings for any invalid [ValidateAssignment] fields
this.ValidateAssignments();
}
}Behavior:
- Inspector feedback: Displays a HelpBox warning (yellow) or error (red) when the field is invalid
-
Runtime validation: Call
this.ValidateAssignments()to log warnings for invalid fields -
Programmatic checking: Call
this.AreAnyAssignmentsInvalid()to check if any fields are invalid - Works with Unity
Objecttypes, strings, collections, and any reference type - Inspector validation runs only in the Unity Editor (stripped in builds for performance)
Visual Reference
Fields marked with [ValidateAssignment] display a HelpBox in the inspector when invalid
The ValidateAssignmentMessageType enum controls how invalid fields are displayed in the inspector:
| Value | Description |
|---|---|
Warning |
Displays a yellow warning HelpBox (default) |
Error |
Displays a red error HelpBox |
The [ValidateAssignment] attribute supports multiple constructor overloads for flexibility:
// Default: warning message type with auto-generated message
[ValidateAssignment]
public GameObject target;
// Inspector shows: "target must be assigned"// Error message type with auto-generated message
[ValidateAssignment(ValidateAssignmentMessageType.Error)]
public AudioSource criticalAudioSource;
// Inspector shows red error: "criticalAudioSource must be assigned"// Warning with custom message
[ValidateAssignment("Enemy name is required for UI display")]
public string enemyName;
// Inspector shows yellow warning: "Enemy name is required for UI display"// Error with custom message
[ValidateAssignment(ValidateAssignmentMessageType.Error, "Spawn points list cannot be empty")]
public List<Transform> spawnPoints;
// Inspector shows red error: "Spawn points list cannot be empty"using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
using System.Collections.Generic;
public class GameConfig : MonoBehaviour
{
// Yellow warning - validates not null
[ValidateAssignment]
public GameObject playerPrefab;
// Red error - validates string not empty/whitespace
[ValidateAssignment(ValidateAssignmentMessageType.Error)]
public string gameTitle;
// Warning with helpful context - validates list not empty
[ValidateAssignment("Add at least one difficulty level")]
public List<string> difficultyLevels;
// Error with specific instructions - validates array not empty
[ValidateAssignment(ValidateAssignmentMessageType.Error, "Spawn points are required - add Transform references")]
public Transform[] spawnPoints;
}Visual Reference
Warning (yellow) and Error (red) HelpBoxes for various invalid field types
Two extension methods are available for runtime validation of [ValidateAssignment] fields:
Logs warnings to the console for all invalid fields:
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class LevelManager : MonoBehaviour
{
[ValidateAssignment]
public GameObject[] enemyPrefabs;
[ValidateAssignment]
public string levelName;
private void Start()
{
// Logs a warning for each invalid [ValidateAssignment] field
this.ValidateAssignments();
}
}Returns true if any [ValidateAssignment] field is invalid:
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
public class SpawnManager : MonoBehaviour
{
[ValidateAssignment]
public GameObject spawnPrefab;
[ValidateAssignment]
public List<Transform> spawnLocations;
private void Start()
{
if (this.AreAnyAssignmentsInvalid())
{
Debug.LogError("SpawnManager has invalid assignments - spawning disabled");
enabled = false;
return;
}
// Safe to proceed - all assignments are valid
SpawnEnemies();
}
}Both attributes validate fields and provide inspector feedback, but they serve different purposes:
| Feature | ValidateAssignment | WNotNull |
|---|---|---|
| Null object check | ✓ | ✓ |
| Empty string check | ✓ | ✗ |
| Empty collection check | ✓ | ✗ |
| Runtime behavior | Logs warnings | Throws ArgumentNullException
|
| Best for | Comprehensive field validation | Strict null reference checking |
When to use which:
- Use
[ValidateAssignment]when you need to validate that strings are non-empty or collections have elements - Use
[WNotNull]when you want strict null checking with an exception thrown at runtime - Use
[ValidateAssignment]when you want softer runtime validation (warnings instead of exceptions) - Use
[WNotNull]for critical references where the game should fail fast if not assigned
public class PlayerSetup : MonoBehaviour
{
// Use WNotNull for critical references - throws if null
[WNotNull(WNotNullMessageType.Error)]
public Rigidbody2D rb;
// Use ValidateAssignment for string validation
[ValidateAssignment]
public string playerName;
// Use ValidateAssignment for collection validation
[ValidateAssignment(ValidateAssignmentMessageType.Error, "Add at least one weapon")]
public List<GameObject> startingWeapons;
private void Awake()
{
// Throws ArgumentNullException if rb is null
this.CheckForNulls();
// Logs warnings if playerName is empty or startingWeapons is empty
this.ValidateAssignments();
}
}using UnityEngine;
using WallstopStudios.UnityHelpers.Core.Attributes;
using System.Collections.Generic;
public class UIManager : MonoBehaviour
{
// Group with validation
[WGroup("Required UI Elements")]
[ValidateAssignment(ValidateAssignmentMessageType.Error)]
public Canvas mainCanvas; // In group
[ValidateAssignment("Button text cannot be empty")]
public string startButtonText; // In group (auto-included)
[ValidateAssignment(ValidateAssignmentMessageType.Error, "Add menu items to display")]
[WGroupEnd("Required UI Elements")] // menuItems IS included, then closes
public List<GameObject> menuItems; // In group (last field)
// Conditional validation
[WShowIf(nameof(useCustomTheme))]
[ValidateAssignment("Custom theme name required when using custom theme")]
public string customThemeName;
public bool useCustomTheme;
}Why Use ValidateAssignment:
- Comprehensive validation: Validates strings, collections, and references, not just null checks
- Visual feedback: See invalid fields immediately in the inspector
- Severity control: Use warnings for nice-to-have fields, errors for critical ones
- Custom messages: Provide helpful context about validation requirements
-
Non-throwing validation: Use
ValidateAssignments()for warnings instead of exceptions -
Programmatic checking: Use
AreAnyAssignmentsInvalid()for conditional logic - Zero runtime cost: All validation stripped from builds
Call CheckForNulls() and ValidateAssignments() in Awake() or Start() to catch missing references immediately:
private void Awake()
{
// Throws for critical null references
this.CheckForNulls();
// Logs warnings for empty strings, collections, etc.
this.ValidateAssignments();
}// Use WNotNull for critical object references (throws on null)
[WNotNull(WNotNullMessageType.Error)]
public Rigidbody2D rb;
// Use ValidateAssignment for strings (validates not empty/whitespace)
[ValidateAssignment]
public string playerName;
// Use ValidateAssignment for collections (validates not empty)
[ValidateAssignment(ValidateAssignmentMessageType.Error)]
public List<Transform> waypoints;[WReadOnly]
public float Speed => rb.velocity.magnitude;// Auto-wired but protected from manual changes
[WReadOnly]
[SiblingComponent]
public Collider2D col;// Required: Must be assigned in inspector
[WNotNull]
public AudioClip attackSound;
// Required: Must not be empty
[ValidateAssignment]
public string characterName;
// Optional: May be null
public AudioClip hitSound;[CreateAssetMenu]
public class GameConfig : ScriptableObject
{
[WNotNull]
public GameObject playerPrefab;
[WNotNull]
public Material defaultMaterial;
[ValidateAssignment("Game title cannot be empty")]
public string gameTitle;
[ValidateAssignment(ValidateAssignmentMessageType.Error)]
public List<string> supportedLanguages;
private void OnEnable()
{
this.CheckForNulls();
this.ValidateAssignments();
}
}- Inspector Grouping Attributes - Organize related fields
- Inspector Conditional Display - Show/hide fields conditionally
- Relational Components - Auto-wire component references
📦 Unity Helpers | 📖 Documentation | 🐛 Issues | 📜 MIT License
- Inspector Button
- Inspector Conditional Display
- Inspector Grouping Attributes
- Inspector Inline Editor
- Inspector Overview
- Inspector Selection Attributes
- Inspector Settings
- Inspector Validation Attributes
- Utility Components
- Visual Components
- Data Structures
- Helper Utilities
- Math And Extensions
- Pooling Guide
- Random Generators
- Reflection Helpers
- Singletons
- Asset Change Detection
- Asset Validation
- Authored Asset Validation
- Editor Tools Guide
- Failed Tests Exporter
- Test Run Reporter
- Unity Method Analyzer





