В чем разница между реализацией интерфейса явно или неявно?

64

В Visual Studio я могу щелкнуть правой кнопкой мыши по интерфейсу и выбрать «Реализовать интерфейс» или «Явно реализовать интерфейс».

Скриншот Visual Studio

public class Test : ITest
{
    public string Id // Generated by Implement Interface
    {
        get { throw new NotImplementedException(); }
    }

    string ITest.Id // Generated by Implement Interface Explicitly
    {
        get { throw new NotImplementedException(); }
    }
}

Единственное различие, которое я вижу между ними, заключается в том, что имя интерфейса добавляется к свойствам и методам интерфейса при их создании, если вы решите явно реализовать интерфейс.

Я нахожу, что это делает код немного более читабельным, так как я могу видеть, откуда взялся этот метод / свойство, однако имеет ли это какое-либо значение в том, как класс используется или компилируется? И действительно ли имеет значение, реализую ли я свои интерфейсы неявно или явно?

Рейчел
источник

Ответы:

51

Проверьте верхний ответ от Эндрю Барретта для "неявной против явной реализации интерфейса" на SO .

В основном:

  • Неявный: вы получаете доступ к интерфейсным методам и свойствам, как если бы они были частью класса.
  • Явный: вы можете получить доступ только к методам и свойствам, рассматривая класс как реализованный интерфейс.

Примеры кода:

Неявные:

Test t = new Test();
t.Id; // OK
((ITest)t).Id; // OK

Явный:

Test t = new Test();
t.Id; // Not OK
((ITest)t).Id; // OK

С точки зрения «когда» вы должны реализовать интерфейс явно, это когда ваш класс уже имеет метод с такой же сигнатурой, что и один из методов вашего интерфейса, или когда ваш класс реализует несколько интерфейсов, которые совместно используют методы с одинаковыми сигнатурами. но несовместимые контракты.

Jalayn
источник
1
Я также нашел явную реализацию полезной, чтобы иметь своего рода «скрытый» интерфейс с небезопасными операциями. Это также делает вызовы этих методов более заметными, что хорошо для небезопасных вещей.
Тамас Селеи
Стоит также упомянуть, что использование явных интерфейсов сопряжено с расходами на производительность, поскольку при каждом обращении к свойству / методу необходимо блокировать / распаковывать объект. Из-за этого лучше использовать неявные интерфейсы, если это возможно
Rachel
3
@ Рейчел: Насколько я знаю, стоимость производительности относится только к типам значений.
Groky
8

Существует также разница в том, как вы вызываете метод.

При использовании явной реализации интерфейса вы должны использовать тип интерфейса для вызова этой конкретной реализации.

Таким образом, при вызове кода вам нужно будет использовать переменную типа ITestдля доступа ITest.Id.

Хорошим примером является статья « Явная реализация интерфейса» (Руководство по программированию в C #) на MSDN.

Одед
источник
4

Это позволяет вам реализовать два интерфейса, которые определяют один и тот же метод. Однако, если вы явно реализуете интерфейс, доступ к методам возможен только тогда, когда переменная введена в этот явный интерфейс.

См. Явное Учебное пособие по Реализации Интерфейса

unholysampler
источник
4

РЕДАКТИРОВАТЬ: Это не должно иметь значения Вы не должны делать это, если ваш класс не реализует два интерфейса с одинаковыми свойствами, так как вам придется привести к соответствующему интерфейсу, прежде чем вы сможете получить доступ к члену:

public interface ITest
{
    string Id { get; }
}

public interface IAlsoTest
{
    string Id { get; }
}

public interface ITestToo
{
    int Id { get; }
}

public class Test : ITest, IAlsoTest
{
    // Valid implicit implementation of BOTH interfaces
    public string Id
    {
        get { throw new NotImplementedException(); }
    }
}

public class TestSeparately : ITest, ITestToo
{
    // This way we can do different things depending
    // on which interface the callee called from.
    string ITest.Id
    {
        get { throw new NotImplementedException(); }
    }

    int ITestToo.Id
    {
        get { throw new NotImplementedException(); }
    }
}

public class TestOuch
{
    public void DoStuff()
    {
        var ts = new TestSeparately();

        // Works
        Console.WriteLine(((ITest)ts).Id);

        // Works
        Console.WriteLine(((ITestToo)ts).Id);

        // Not valid! Which one did we want to call?
        Console.WriteLine(ts.Id);
    }
}

Пример использования имеет место, когда вы явно реализуете элемент интерфейса, даже если вы используете только один интерфейс (который я всегда забываю: S), поэтому я постараюсь избегать явной реализации, когда это возможно, поскольку она будет скрывать членов класса, если они ' не приводить к правильному интерфейсу (что довольно запутанно).

Эд Джеймс
источник
3

Основываясь на ответе Джалаяна,

  • Неявный: вы получаете доступ к интерфейсным методам и свойствам, как если бы они были частью класса.
  • Явный: вы можете получить доступ только к методам и свойствам, рассматривая класс как реализованный интерфейс.

введите описание изображения здесь

Александр Залдостанов
источник