ความแตกต่างหลัก
| คุณสมบัติ | Abstract Class | Interface |
| Implementation | มีได้ทั้ง Abstract และ Concrete Members | C# 8-: Signature เท่านั้น C# 8+: Default Implementation ได้ |
| Inheritance | Single Inheritance (class A : Base) | Multiple Implementation (class A : I1, I2) |
| Constructor | มีได้ (Protected/Public) | ไม่มี |
| Fields/State | มีได้ (Instance/Static Fields) | ไม่มี Instance Fields (C# 8+ มี Static Fields) |
| Access Modifiers | ทุกอย่าง (private, protected, public, internal...) | C# 8-: public เท่านั้น C# 8+: private, protected, internal, static |
| Performance | เร็วกว่า (Direct Call/Non-virtual) | ช้ากว่าเล็กน้อย (Interface Dispatch) |
| Versioning | เพิ่ม Member ได้ (Non-breaking) | C# 8-: Breaking Change C# 8+: Default Impl = Non-breaking |
| Usage | "Is-A" Relationship, Shared Implementation | "Can-Do" Contract, Capability |
Abstract Class - ตัวอย่าง
public abstract class Animal
{
// State (Fields)
public string Name { get; set; }
public int Age { get; protected set; }
// Constructor
protected Animal(string name)
{
Name = name;
}
// Concrete Method (Shared Implementation)
public void Eat()
{
Console.WriteLine($"{Name} is eating...");
}
// Abstract Method (Must Override)
public abstract void MakeSound();
// Virtual Method (Can Override)
public virtual void Sleep()
{
Console.WriteLine($"{Name} is sleeping...");
}
}
public class Dog : Animal
{
public Dog(string name) : base(name) { }
public override void MakeSound()
{
Console.WriteLine("Woof!");
}
public override void Sleep()
{
base.Sleep(); // Call Base
Console.WriteLine("...dreaming of bones");
}
}
Interface - ตัวอย่าง (C# 8+ Features)
public interface IAnimal
{
// Contract (Implicitly Public)
string Name { get; set; }
void MakeSound();
// Default Implementation (C# 8+)
void Eat()
{
Console.WriteLine($"{Name} is eating...");
}
// Static Members (C# 8+)
static int Count { get; set; }
// Private Helper (C# 8+)
private void Log(string msg) => Console.WriteLine($"[LOG] {msg}");
// Protected (C# 8+) - For Implementers
protected virtual void OnSoundMade() { }
}
public class Cat : IAnimal
{
public string Name { get; set; }
public void MakeSound()
{
Console.WriteLine("Meow!");
OnSoundMade(); // Can Call Protected
}
}
Multiple Interfaces vs Single Abstract
// Class สามารถ Implement Interfaces หลายตัว
public class FlyingFish : IFly, ISwim, IAnimal
{
// Implement ทั้ง 3 Interfaces
public void Fly() { ... }
public void Swim() { ... }
public void MakeSound() { ... }
}
// แต่ Extend Abstract Class ได้เพียง 1 ตัว
// public class FlyingFish : Animal, IFly // ❌ Error: Multiple Base Classes
public class FlyingFish : Animal, IFly // ✅ OK: 1 Base Class + Interfaces
{
// ...
}
Pattern: Abstract Class + Interface (Best of Both)
// Interface = Contract
public interface IRepository
{
T GetById(int id);
void Save(T entity);
}
// Abstract Base = Shared Implementation
public abstract class RepositoryBase : IRepository
{
protected readonly DbContext Context;
protected RepositoryBase(DbContext context)
{
Context = context;
}
// Shared Implementation
public virtual T GetById(int id) => Context.Set().Find(id);
public virtual void Save(T entity) => Context.Set().Add(entity);
// Abstract - Force Implement
public abstract void Delete(T entity);
}
// Concrete
public class UserRepository : RepositoryBase, IRepository
{
public UserRepository(DbContext context) : base(context) { }
public override void Delete(User entity) => Context.Users.Remove(entity);
}
Decision Guide
ต้องการอะไร? ใช้ตัวไหน?
────────────────────────────────────────────────
Shared Code/State ระหว่าง Related Types Abstract Class
Multiple Implementations / Capabilities Interface
Need Constructor / Fields Abstract Class
Plugin/Extensibility Model Interface
Versioning (Add Methods Later) Interface (C# 8+ Default Impl)
Simple Contract / Marker Interface
Framework Base Class Abstract Class
Modern C#: Records + Interfaces
// Data Contract
public interface IUserDto
{
string Name { get; }
string Email { get; }
}
// Implementation as Record (Immutable, Value Equality)
public record UserDto(string Name, string Email) : IUserDto;
// Usage
IUserDto user = new UserDto("John", "john@email.com");