| name | unity-csharp-fundamentals |
| description | Unity C# fundamental patterns including TryGetComponent, SerializeField, RequireComponent, and safe coding practices. Essential patterns for robust Unity development. Use PROACTIVELY for any Unity C# code to ensure best practices. |
| requires | ["csharp-plugin:csharp-code-style","csharp-plugin:csharp-xml-docs"] |
Unity C# Fundamentals - Essential Coding Patterns
Overview
Core Unity C# patterns for safe, maintainable code. Not optimizations but fundamental practices.
Foundation Required: C# basics, Unity MonoBehaviour lifecycle
Core Topics: TryGetComponent, SerializeField, RequireComponent, Null-safe patterns, Lifecycle management
Essential Patterns
TryGetComponent (Required)
Always use TryGetComponent instead of GetComponent:
Rigidbody rb = GetComponent<Rigidbody>();
rb.velocity = Vector3.zero;
Rigidbody rb;
if (TryGetComponent(out rb))
{
rb.velocity = Vector3.zero;
}
private Rigidbody mRb;
void Awake()
{
if (!TryGetComponent(out mRb))
{
Debug.LogError($"Missing Rigidbody on {gameObject.name}", this);
}
}
Global Object Search (Unity 2023.1+)
GameManager manager = FindObjectOfType<GameManager>();
GameManager manager = FindAnyObjectByType<GameManager>();
GameManager manager = FindFirstObjectByType<GameManager>();
Enemy[] enemies = FindObjectsByType<Enemy>(FindObjectsSortMode.None);
SerializeField Pattern
public float speed;
[SerializeField] private float mSpeed = 5f;
[SerializeField, Tooltip("Units/second"), Range(0f, 100f)]
private float mMoveSpeed = 5f;
public float Speed => mSpeed;
RequireComponent
[RequireComponent(typeof(Rigidbody))]
[DisallowMultipleComponent]
public class PhysicsObject : MonoBehaviour
{
private Rigidbody mRb;
void Awake()
{
TryGetComponent(out mRb);
}
}
Unity Null Safety
Transform target = mCached ?? FindTarget();
mEnemy?.TakeDamage(10);
Transform target = mCached != null ? mCached : FindTarget();
if (mEnemy != null)
{
mEnemy.TakeDamage(10);
}
Lifecycle Order
void Awake() { }
void OnEnable() { }
void Start() { }
void OnDisable() { }
void OnDestroy() { }
Unity C# 9.0 Limitations
Important: Unity's Mono/IL2CPP runtime lacks IsExternalInit.
init accessor causes compile error CS0518.
public string Name { get; private init; }
public string Name { get; private set; }
private readonly string mName;
public string Name => mName;
Available: Pattern matching, switch expressions, covariant returns
NOT Available: init, required (C# 11)
Quick Reference
| Pattern | Rule |
|---|
| Component access | Always TryGetComponent, never bare GetComponent |
| Serialization | [SerializeField] private, not public |
| Dependencies | Use [RequireComponent] for guaranteed components |
| Null checks | Explicit != null, not ?? or ?. |
| Caching | Get in Awake, reuse everywhere |
| Events | Subscribe in OnEnable, unsubscribe in OnDisable |
| Global search | FindAnyObjectByType (fastest), not FindObjectOfType |
Reference Documentation
- TryGetComponent variations and interface-based access
- GetComponentInChildren/Parent patterns
- Allocation-free multiple component access
- Caching strategies and performance comparisons
- Complete serialization attribute reference
- Inspector customization (Header, Tooltip, Range)
- Execution order control
- Conditional compilation
init accessor alternatives with code examples
- Records in Unity (limitations and workarounds)
required modifier alternatives
- Available C# 9.0 features in Unity