Do С# 8 реализации интерфейса по умолчанию допускают множественное наследование

Согласно https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/, одной из новых функций, появившихся в С# 8, является реализация интерфейсов по умолчанию. Будет ли эта новая функция также неявно разрешать множественное наследование? Если нет, что именно произойдет, если я попробую следующее:

public interface A { int Foo() => 1; }
public interface B { int Foo() => 2; }
public class C : A, B { }

Ответ 1

Благодарим @CodeCaster за его/ее замечательные комментарии, которые вызвали этот ответ.

предложение гласит:

Обратите внимание, что класс не наследует членов от своих интерфейсов; это эта функция не изменяется:

Таким образом, кажется разумным (хотя невозможно подтвердить со 100% уверенностью до его отправки), что:

public interface A { int Foo() => return 1; }
public interface B { int Foo() => return 2; }
public class C : A, B { }

будет работать нормально.

Как показано в предложении:

new C().M(); // error: class 'C' does not contain a member 'M'

тогда мы можем предположить, ваша версия:

new C().Foo();

также не будет компилироваться.

Предложение показывает:

IA i = new C();
i.M();

как действительный, что эквивалентно вашему:

A i = new C();
i.Foo();

Поскольку i объявлен как тип A, нет никаких оснований предполагать, что то же самое не будет работать, если A было изменено на B - нет никаких коллизий, о которых можно говорить.

Весь смысл этой функции - обеспечить безопасное расширение интерфейсов (см. это видео). Если это только сработало, если вы реализовали один интерфейс, это, кажется, противоречит цели функции. И, учитывая, что эта функция, по-видимому, реализована способом, примерно схожим с явной реализацией интерфейса (именно поэтому мы не можем напрямую вызывать C.Foo()), я думаю, что мы можем разумно предположить, что она, скорее всего, допускает реализацию нескольких интерфейсов.

Ответ 2

На ваш вопрос ответила Мадс Торгерсен в сообщении в блоге, на которое вы ссылались:

На самом деле интерфейсы все еще довольно далеки от абстрактных классов. Классы не наследуют членов от интерфейсов, поэтому, если класс оставляет член M, реализованный интерфейсом, класс не имеет члена M! Это похоже на явную реализацию сегодня; Вы должны преобразовать в интерфейс, чтобы добраться до таких участников.

Итак, с вашим примером:

public interface A { int Foo() => 1; }
public interface B { int Foo() => 2; }
public class C : A, B { }

Ты не сможешь это сделать:

var something = new C();
var x = something.Foo(); /* does not compile */

Вы можете сделать следующее:

var something = new C();
var x = ((A)something).Foo(); /* calls the implementation provided by A */
var y = ((B)something).Foo(); /* calls the implementation provided by B */

Ответ 3

Могу ли я предложить лучший пример:

Фаза 1: Сборка А:

public interface A { int AFoo(); }

AssemblyB:

public interface B { int BFoo(); }

AssemblyC:

public interface C : A,B {}

MainAssembly:

public class D : C
{
public int AFoo() {return 1;}
public int BFoo() {return 2;}
}
...
C d = new D();

В этом взоре все работает отлично.

Faze 2: просто замена двух сборок: AssemblyA:

public interface A 
{
   int AFoo();
   int Foo() => AFoo();
}

AssemblyB:

public interface B
{
   int BFoo();
   int Foo() => BFoo();
}

И теперь у нас есть проблема, как это решит d.Foo(); ?