Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C#

Khác biệt giữa Method Overriding và Method Hiding trong C#

Tóm tắt nhanh

Đặc điểmMethod OverridingMethod Hiding (Shadowing)
Từ khóavirtual + overridenew
PolymorphismCó (runtime polymorphism)Không (compile-time binding)
Base reference → Derived objectGọi derived methodGọi base method
Derived reference → Derived objectGọi derived methodGọi derived method
Truy cập base implementationbase.Method()Không trực tiếp (cần cast)
Mục đíchMở rộng/thay đổi hành viĐặt tên trùng, thay đổi signature, break inheritance

Method Overriding (Ghi đè)


public class Animal 
{
    public virtual void MakeSound() 
    {
        Console.WriteLine("Animal sound");
    }
}

public class Dog : Animal 
{
    public override void MakeSound() 
    {
        Console.WriteLine("Woof!");
        // base.MakeSound(); // Có thể gọi base
    }
}

// Polymorphism hoạt động
Animal animal = new Dog();
animal.MakeSound(); // "Woof!" - Gọi Dog.MakeSound()

Method Hiding (Che giấu)


public class Animal 
{
    public void MakeSound() 
    {
        Console.WriteLine("Animal sound");
    }
}

public class Dog : Animal 
{
    // new keyword - hiding base method
    public new void MakeSound() 
    {
        Console.WriteLine("Woof!");
    }
}

// Polymorphism KHÔNG hoạt động
Animal animal = new Dog();
animal.MakeSound(); // "Animal sound" - Gọi Animal.MakeSound()!

Dog dog = new Dog();
dog.MakeSound();    // "Woof!" - Gọi Dog.MakeSound()

So sánh hành vi chi tiết


public class Base 
{
    public virtual void VirtualMethod() => Console.WriteLine("Base.Virtual");
    public void NonVirtualMethod() => Console.WriteLine("Base.NonVirtual");
}

public class Derived : Base 
{
    public override void VirtualMethod() => Console.WriteLine("Derived.Virtual");
    public new void NonVirtualMethod() => Console.WriteLine("Derived.NonVirtual");
}

class Program 
{
    static void Main() 
    {
        Base b = new Base();
        Derived d = new Derived();
        Base bd = new Derived(); // Base reference, Derived object
        
        Console.WriteLine("--- Base instance ---");
        b.VirtualMethod();      // Base.Virtual
        b.NonVirtualMethod();   // Base.NonVirtual
        
        Console.WriteLine("--- Derived instance ---");
        d.VirtualMethod();      // Derived.Virtual
        d.NonVirtualMethod();   // Derived.NonVirtual
        
        Console.WriteLine("--- Base ref to Derived obj ---");
        bd.VirtualMethod();     // Derived.Virtual (OVERRIDE works!)
        bd.NonVirtualMethod();  // Base.NonVirtual (HIDING - base method!)
        
        // Ép kiểu để gọi hidden method
        ((Derived)bd).NonVirtualMethod(); // Derived.NonVirtual
    }
}

Kết quả

--- Base instance ---
Base.Virtual
Base.NonVirtual
--- Derived instance ---
Derived.Virtual
Derived.NonVirtual
--- Base ref to Derived obj ---
Derived.Virtual
Base.NonVirtual
Derived.NonVirtual

Khi nào dùng Overriding vs Hiding?

Dùng Overriding (virtual/override) khi:

  • Muốn polymorphism - hành vi thay đổi theo runtime type.
  • Mở rộng chức năng base class (template method pattern).
  • Thiết kế cho extensibility (plugin, framework).

Dùng Hiding (new) khi:

  • Base class không phải virtual (sealed, third-party, legacy).
  • Thay đổi signature (tham số, return type).
  • Tên method trùng nhưng ngữ nghĩa hoàn toàn khác.
  • Versioning: base class thêm method mới trùng tên với derived class cũ.

Versioning Scenario (Tại sao cần new)


// Version 1.0 - Base library
public class Logger 
{
    public void Log(string message) { Console.WriteLine(message); }
}

// Version 1.0 - Your code
public class MyLogger : Logger 
{
    public void Log(string message, LogLevel level) { ... } // Overload
}

// Version 2.0 - Base library thêm method mới
public class Logger 
{
    public void Log(string message) { ... }
    public void Log(string message, LogLevel level) { ... } // NEW!
}

// Your code compile với v2.0:
// Warning: 'MyLogger.Log(string, LogLevel)' hides inherited member 'Logger.Log(string, LogLevel)'. 
// Use 'new' keyword if hiding was intended.

// Fix: Thêm new keyword
public new void Log(string message, LogLevel level) { ... }

Warning CS0108

Nếu không dùng new khi hiding → Compiler warning CS0108: "Member hides inherited member. Use 'new' keyword if hiding was intended."

Sealed Override


public class Base 
{
    public virtual void Method() { }
}

public class Middle : Base 
{
    public sealed override void Method() { } // Không cho derived override nữa
}

public class Derived : Middle 
{
    // public override void Method() { } // ❌ Error: cannot override sealed method
    public new void Method() { } // Chỉ có thể hiding
}

Best Practices

  1. Mặc định: virtual/override cho polymorphism.
  2. Chỉ dùng new khi bắt buộc (base không virtual, versioning conflict).
  3. Luôn thêm new explicit khi hiding để tắt warning và thể hiện ý định.
  4. XML doc: <inheritdoc/> cho override, doc riêng cho hiding.
  5. Code review: Kiểm tra hiding có ý định không.