Ответ
Для разрешения конфликта имен методов из разных интерфейсов используется явная реализация интерфейса (explicit interface implementation). Этот подход позволяет предоставить отдельные реализации для каждого интерфейса.
Ключевые моменты:
- Метод, реализованный явно, не имеет модификатора доступа (
public,privateи т.д.). - Вызвать такой метод можно только через переменную, приведенную к типу конкретного интерфейса.
- Это единственный чистый способ в C# решить данную проблему без изменения сигнатур методов в интерфейсах.
Пример:
interface ILogger
{
void Write(string message);
}
interface IDebugger
{
void Write(string message);
}
class MultiWriter : ILogger, IDebugger
{
// Стандартная (неявная) реализация для ILogger
public void Write(string message)
{
Console.WriteLine($"[LOG] {message}");
}
// Явная реализация для IDebugger
void IDebugger.Write(string message)
{
Console.WriteLine($"[DEBUG] {message}");
}
}
// Использование:
var writer = new MultiWriter();
// Вызывает реализацию ILogger.Write
writer.Write("Application started");
// Для вызова IDebugger.Write требуется приведение
((IDebugger)writer).Write("Checking state");
// Или через переменную интерфейсного типа
IDebugger debugWriter = writer;
debugWriter.Write("Debug info");
Практический совет: Используйте явную реализацию, когда метод имеет разную семантику в разных интерфейсах, и вы хотите четко разделить это поведение в коде.
Ответ 18+ 🔞
Давай разжую эту тему, а то некоторые думают, что если два интерфейса говорят "напиши Write", то можно один метод нарисовать и всем угодить. Ага, щас, как же! Получишь конфликт имён, и компилятор тебе такое предъявит, что мало не покажется.
Вот смотри, в чём суть. Есть у тебя два интерфейса, и в них метод называется одинаково — void Write(string message). Класс должен реализовать оба. Если ты просто попробуешь написать один публичный метод Write, то компилятор офигеет: "Чувак, это реализация для кого? Для ILogger или для IDebugger? Я нихуя не понимаю!"
И тут на сцену выходит явная реализация интерфейса — наш спаситель, блядь. Это такой специальный синтаксис, где ты привязываешь конкретную реализацию метода к конкретному интерфейсу, и делаешь это втайне от общего API своего класса.
Как это выглядит? А вот как, смотри:
interface ILogger
{
void Write(string message);
}
interface IDebugger
{
void Write(string message);
}
class MultiWriter : ILogger, IDebugger
{
// Это — обычная, неявная реализация. Она считается реализацией для ILogger.
// Её можно вызвать просто так, с объекта.
public void Write(string message)
{
Console.WriteLine($"[LOG] {message}");
}
// А это — явная реализация для IDebugger.
// Видишь? Никакого модификатора доступа (public/private)!
// И имя метода — это полное имя интерфейса + точка + имя метода.
void IDebugger.Write(string message)
{
Console.WriteLine($"[DEBUG] {message}");
}
}
Теперь самый сок, как этим пользоваться:
var writer = new MultiWriter();
// Эта строка вызовет обычный публичный метод, то есть реализацию для ILogger.
writer.Write("Application started"); // Выведет: [LOG] Application started
// А чтобы вызвать метод из IDebugger, нужно привести объект к этому интерфейсу.
// Иначе этот метод просто спрятан, как грех за пазухой.
((IDebugger)writer).Write("Checking state"); // Выведет: [DEBUG] Checking state
// Или так, через переменную нужного типа — ещё понятнее.
IDebugger debugWriter = writer;
debugWriter.Write("Debug info"); // Выведет: [DEBUG] Debug info
Вот и вся магия, ёпта. Явная реализация — это как потайной карман. Метод есть, но добраться до него можно только через "дверь" конкретного интерфейса. Прямо с объекта класса его не вызовешь, он там невидимый.
Когда это реально полезно? Ну, например, когда у интерфейсов методы с одним именем, но смысл у них разный, как в нашем примере: логирование и отладка — это же две большие разницы, блядь. Или представь интерфейсы ISaveToFile и ISaveToDatabase, оба с методом Save(). Логично же сделать разную реализацию для каждого случая, а не один метод, который пытается быть и тем, и другим, превращаясь в говнокод.
Так что запомни: когда компилятор начинает ныть про неоднозначность — не паникуй, не пытайся переименовывать методы в интерфейсах (это обычно пиздец и нарушение контрактов). Просто сделай явную реализацию для одного из интерфейсов, или для обоих, и живи спокойно. Всё гениальное просто, как три копейки.