C# Inheritance and Interface Implementation in Unity Development

Understanding Derived Classes and Interface Implementations

Derived Classes (Inheritance)

Derived classes use the : symbol to inherit from a base class, gaining access to all non-private members (fields, methods, properties) and can override or extend functionality.

Common Unity Usage:

  • All MonoBehaviour scripts implicitly inherit from UnityEngine.Object
  • Creating a base GameEntity class with derived Hero and Monster classes sharing common movement and health logic
public abstract class GameEntity : MonoBehaviour
{
    public virtual void Move() { /* Default movement implementation */ }
}

public class Hero : GameEntity
{
    public override void Move() { /* Hero-specific movement logic */ }
}

Implementation Classes (Interfaces)

Classes implement interfaces using the : symbol, providing concrete implementations for all interface members.

Common Unity Usage:

  • Defining IHittable interface for characters, structures, and items that can receive damage
  • Creating IInteractive interface for doors, chests, and NPCs that support player interaction
public interface IHittable
{
    void ReceiveHit(int damageValue);
}

public class Hero : MonoBehaviour, IHittable
{
    public void ReceiveHit(int damageValue) { /* Damage handling implementation */ }
}

Common Implementation Pitfalls

Pitfall 1: Misusing Interfaces as Abstract Classes

Incorrect Approach:

public interface IGameCharacter
{
    public int HitPoints { get; set; } // Interfaces cannot contain fields!
    void PerformAttack();
}

Issue: Interfaces can only declare members, not contain fields or implementations.

Solution: Use abstract classes or properties instead.

Pitfall 2: Excessive Inheritance Leading to Tight Coupling

Incorrect Approach:

public class Hero : GameEntity, IHittable, IMovable, IAttacker, IStorage...
{
    // Class becomes bloated and difficult to maintain
}

Issue: Long inheritance chains create dependencies where base class changes affect all derived classes.

Solution: Prefer interface composition (e.g., IHittable + IMovable) over deep inheritance hierarcheis.

Pitfall 3: Overlooking Unity's Execution Order

Incorrect Approach:

public class Monster : GameEntity
{
    void Start() { /* Initialization logic */ }
    public override void Move() { /* Uses uninitialized variables */ }
}

Issue: Start() may execute after Move() is called, causing null reference exceptions.

Solution: Initialize critical variables in Awake() or use [SerializeField] for pre-assignment.

Key Differences Between Inheritance and Interfaces

Feature Derived Classes (Inheritance) Implementation Classes (Interfaces)
Purpose Code reuse and behavior inheritance Defining contracts and decoupling
Member Restrictions Can contain fields, concrete methods, constructors Only method, property, and event declarations
Multiple Inheritance Single inheritance (C# limitation) Multiple implementation (class can implement multiple interfaces)
Typical Unity Use Cases Base entity classes, UI controllers, utility base classes Interaction systems, damage systems, save systems

Recommended Development Practices

Practice 1: Prefer Interfaces for Behavior Defniition

Have interactive objects implement IInteractive rather than inheriting from an InteractiveBase class. This prevents inheritance chain bloat and facilitates unit testing through interface mocking.

Practice 2: Use Abstract Classes for Default Implementations

Define GameEntity as an abstract class providing default Move() logic while allowing derived classes to override it. This reduces code duplication while maintaining extensibility.

Practice 3: Avoid "God Objects"

Instead of creating a monolithic GameObjectBase containing all possible functionality (movement, combat, UI, saving), split functionality into separate interfaces/components like IMovable, IHittable, and ISavable.

Practice 4: Leverage Unity's Component Architecture

Implement interfaces as separate MonoBehaviour components rather than embedding them directly in entity scripts:

public class DamageHandler : MonoBehaviour, IHittable
{
    public void ReceiveHit(int damageValue) { /* Damage handling logic */ }
}

This allows flexible addition/removal of functionality through the Inspector.

Development Insights

  • Inheritance represents "is-a" relationships (Hero is a GameEntity), suitable for hierarchical structures
  • Interfaces represent "can-do" relationships (Hero can ReceiveHit), ideal for capability definitions
  • In Unity, prefer interface composition with component-based architecture over deep inheritance hierarchies
  • Always consider Unity's lifecycle - place initialization logic in Awake() rather than constructors

Tags: C# unity Inheritance interfaces GameDevelopment

Posted on Sun, 02 Aug 2026 16:31:02 +0000 by navid