Vấn đề: Trùng tên thành viên trong nhiều Interface
Khi một class implement nhiều interface có phương thức cùng tên, cùng signature, triển khai ngầm (implicit) sẽ gộp chung một implementation cho tất cả interface.
Explicit Implementation giải quyết vấn đề này
- Cú pháp:
InterfaceName.MethodName() - Method không có access modifier (implicit private).
- Chỉ có thể gọi khi cast đối tượng về interface cụ thể.
- Cho phép implementation khác nhau cho từng interface.
Ví dụ cơ bản
interface ICar
{
void Display();
}
interface IBike
{
void Display();
}
class ShowRoom : ICar, IBike
{
// Explicit implementation cho ICar
void ICar.Display()
{
Console.WriteLine("Hiển thị thông tin xe hơi");
}
// Explicit implementation cho IBike
void IBike.Display()
{
Console.WriteLine("Hiển thị thông tin xe máy");
}
}
class Program
{
static void Main()
{
var showroom = new ShowRoom();
// ❌ Không thể gọi trực tiếp: showroom.Display(); // Compile Error
// ✅ Phải cast về interface
ICar car = showroom;
car.Display(); // Output: Hiển thị thông tin xe hơi
IBike bike = showroom;
bike.Display(); // Output: Hiển thị thông tin xe máy
// Hoặc cast trực tiếp
((ICar)showroom).Display();
((IBike)showroom).Display();
}
}
Kết hợp Implicit + Explicit
interface ILogger
{
void Log(string message);
}
interface IAuditable
{
void Log(string message);
}
class Service : ILogger, IAuditable
{
// Implicit implementation - dùng cho ILogger (mặc định)
public void Log(string message)
{
Console.WriteLine($"[LOG] {message}");
}
// Explicit implementation - chỉ cho IAuditable
void IAuditable.Log(string message)
{
Console.WriteLine($"[AUDIT] {DateTime.Now}: {message}");
}
}
// Sử dụng
var service = new Service();
service.Log("User login"); // [LOG] User login (implicit)
ILogger logger = service;
logger.Log("User login"); // [LOG] User login
IAuditable audit = service;
audit.Log("User login"); // [AUDIT] 2024-01-15 10:30: User login
Khi nào dùng Explicit Implementation?
| Trường hợp | Giải pháp |
|---|---|
| Hai interface có method trùng tên/signature | Bắt buộc explicit cho ít nhất một |
| Muốn ẩn method khỏi public API của class | Explicit (chỉ gọi qua interface) |
| Implementation khác nhau cho từng interface | Explicit cho từng interface |
| Implement interface cũ (legacy) nhưng không muốn lộ API | Explicit |
| Property/Event trùng tên | Explicit implementation |
Explicit Property Implementation
interface IReadOnly
{
string Name { get; }
}
interface IWriteOnly
{
string Name { set; }
}
class Entity : IReadOnly, IWriteOnly
{
private string _name;
// Explicit get cho IReadOnly
string IReadOnly.Name => _name;
// Explicit set cho IWriteOnly
string IWriteOnly.Name
{
set => _name = value?.Trim();
}
}
Explicit Event Implementation
interface INotifier
{
event EventHandler Notified;
}
class Service : INotifier
{
private event EventHandler _notified;
event EventHandler INotifier.Notified
{
add => _notified += value;
remove => _notified -= value;
}
public void Trigger() => _notified?.Invoke(this, EventArgs.Empty);
}
Lưu ý quan trọng
- Explicit implementation members là implicitly private - không thể dùng
public,private,protected. - Không thể gọi trực tiếp trên instance class - phải cast.
- Virtual/Abstract: Explicit implementation có thể
virtual(trong class abstract/base) để derived class override. - Interface default implementation (C# 8+): Có thể cung cấp default body trong interface, class không cần implement.
Virtual Explicit Implementation
interface IPlugin
{
void Execute();
}
abstract class PluginBase : IPlugin
{
// Virtual explicit - cho derived override
public virtual void IPlugin.Execute()
{
Console.WriteLine("Base execution");
}
}
class MyPlugin : PluginBase
{
// Override explicit implementation
public override void IPlugin.Execute()
{
Console.WriteLine("Custom execution");
}
}