Когда мы должны использовать метод интерфейса по умолчанию в C#? - PullRequest
6 голосов
/ 10 июля 2020

В C# 8 и позже у нас есть методы интерфейса по умолчанию , поэтому:

Не разрушает принцип of interface ?

Когда следует использовать методы интерфейса по умолчанию вместо базового (абстрактного) класса ?

Ответы [ 2 ]

5 голосов
/ 10 июля 2020

Почему у нас есть интерфейсы?

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

Так почему у нас оба в C#? Зачем вообще нужны интерфейсы? Разве мы не можем просто определить интерфейс как абстрактный класс, как мы это делаем, например, в C ++?

Причина этого - проблема ромба : ( Источник изображения )

enter image description here

If both B and C implement A.DoSomething() differently, which implementation should D inherit? That's a hard problem, and the Java as well as the C# designers decided to avoid it by allowing multiple inheritance only for special base types which do not include any implementation. They decided to call these special base types interfaces.

So, there is no "principle of interface". Interfaces are just a "tool" to solve a particular problem.

So why do we need default implementations?

Backwards compatibility. You wrote a vastly successful library used by thousands of developers worldwide. Your library contains some interface I, and now you decide that you need an extra method M on it. The problem is:

  • You can't add another method M to I, because that would break existing classes implementing I (because they don't implement M), and
  • you can't change I to an abstract base class, because that, as well, would break existing classes implementing I, and you will lose the ability to do multiple inheritance.

So how do default implementations avoid the diamond problem?

By not inheriting those default methods (example inspired by the one in эта статья , некоторые интересные угловые случаи см. В полной статье):

interface I1
{
    void M() { Console.WriteLine("I1.M"); } // default method
}

interface I2
{
    void M() { Console.WriteLine("I2.M"); } // default method
}

class C : I1, I2 { }

class Program
{
    static void Main(string[] args)
    {
        // c, i1 and i2 reference the same object
        C c = new C();
        I1 i1 = c;
        I2 i2 = c;

        i1.M(); // prints "I1.M"
        i2.M(); // prints "I2.M"
        c.M();  // compile error: class 'C' does not contain a member 'M'
    }
}
1 голос
/ 10 июля 2020

Как объясняется в документации , существует два основных приложения:

Расширение существующих API

Методы виртуального расширения позволяют автору API добавлять методы интерфейса в будущих версиях без нарушения исходной или двоичной совместимости с существующими реализациями этого интерфейса.

Таким образом, он предназначен как средство для расширения API (= набора интерфейсов) без необходимости обновления все существующие реализации (поскольку они должны реализовывать только что добавленные функции).

Шаблон признаков

Шаблон признаков позволяет расширить класс несколькими наборами предварительных реализованные методы. Это невозможно с абстрактными классами: данный класс может наследовать только от одного родительского класса, но от нескольких интерфейсов.

Обратите внимание, что эта функция связана с проблемой алмазного наследования . Таким образом, помимо этих c приложений, эта функция не должна использоваться для замены абстрактных классов.

...