Относится ли реализация по умолчанию членов интерфейса в C# 8 к решению проблемы множественного наследования абстрактного класса?
Я читаю этот блог .NET Engineering Team
и они представили новую функцию реализации по умолчанию для Interface
, Я запутался в связи с его мотивом, кроме проблемы многоуровневого наследования abstract class
, Кроме этого, я не могу понять какую-либо другую выгоду. Создайте следующий код:
C# 7 (невозможно предоставить определения методов)
interface ILogger
{
void LogData(dynamic data, dynamic logMode);
bool SendStatusEmail(string emailAddress);
}
public class EmployeeLog : ILogger
{
public void LogData(dynamic data, dynamic logMode)
{
throw new NotImplementedException();
}
public bool SendStatusEmail(string emailAddress)
{
throw new NotImplementedException();
}
}
public abstract class Logger
{
public abstract void LogData(dynamic data, dynamic logMode);
public bool SendStatusEmail(string emailAddress)
{
// Email Sending Code
return true;
}
}
public class EmployeeLog : Logger
{
public override void LogData(dynamic data, dynamic logMode)
{
throw new NotImplementedException();
}
}
C# 8 (можно предоставить определения методов)
interface ILogger
{
void LogData(dynamic data, dynamic logMode);
public bool SendStatusEmail(string emailAddress)
{
// Email Sending Code
return true;
}
}
public class EmployeeLog : ILogger
{
public void LogData(dynamic data, dynamic logMode)
{
throw new NotImplementedException();
}
}
public abstract class Logger
{
public abstract void LogData(dynamic data, dynamic logMode);
public bool SendStatusEmail(string emailAddress)
{
// Email Sending Code
return true;
}
}
public class EmployeeLog : Logger
{
public override void LogData(dynamic data, dynamic logMode)
{
throw new NotImplementedException();
}
}
В C# 8
, и то и другое abstract class
а также interface
может выполнить ту же работу, что и реализация по умолчанию для своих членов. У меня есть следующие сомнения, связанные с этим:
Если интерфейс обеспечивает реализацию по умолчанию, а также поддерживает множественное наследование, зачем нуждаться в абстрактном классе в C# 8?
Что будет в случае этого сценария?
:
interface ILogger
{
public bool SendStatusEmail(string emailAddress)
{
// Email Sending Code
return true;
}
}
interface IEmail
{
public bool SendStatusEmail(string emailAddress)
{
// Email Sending Code
return true;
}
}
public class EmployeeLog : ILogger, IEmail
{
}
public class Test
{
EmployeeLog emp = new EmployeeLog();
emp.SendStatusEmail(); //Which function it will refer to?
}
0 ответов
Ответ: Абстрактные классы могут иметь поля и виртуальные методы.
Вот почему множественное наследование не поддерживается в C# (также в Java).
Поля с множественным наследованием могут вызывать проблемы, когда:
class A : B, C {...}
class C : D {...}
class B : D {...}
class D
{
...
protected int _value;
...
}
Если унаследованное B
а также C
использовать один и тот же экземпляр _value
?
И тому и другому есть причины.
Если так, то логика в B
а также C
могут мешать друг другу, потому что значение _value
не предсказуемо для B
ни для C
.
А также B
а также C
даже не подозревают, что они будут работать друг с другом как части одного объекта.
Если нет, то какой экземпляр _value
должен быть доступен из A
?
Аналогичные проблемы применимы и к виртуальным методам. Поскольку виртуальная таблица больше не будет линейной, когда обаB
а также C
переопределить виртуальный метод, определенный в D
.
Их решение сделало бы отношения наследования очень сложными, поэтому Java не поддерживает множественное наследование и ввела концепцию интерфейса, и это также пришло в C#.
Как интерфейс решил эту проблему
В определениях интерфейсов есть только объявления методов (относительно свойств как средств доступа как методов), поэтому не может быть полей и переопределений методов. Таким образом, нет проблем множественного наследования.
Как C# 8.0 может позволить интерфейсам иметь тела методов, не вызывая этих проблем
Реализация по умолчанию в C# 8.0 не использует ту же логику, что и виртуальная таблица в логике наследования классов, а использует механизм приоритета, который выбирает реализацию из ближайшего реализованного интерфейса как единственную доступную реализацию, поэтому проблем с виртуальными таблицами нет.
В интерфейсах по-прежнему нет разрешенных полей, поэтому проблем с полями нет.
Как выбрать между интерфейсом с реализациями по умолчанию и абстрактными классами
Синтаксически, если тип должен иметь поля или виртуальные / абстрактные методы с несколькими используемыми переопределениями, из типов в дереве наследования используйте абстрактный класс, в противном случае - интерфейс.
По логике вещей, если основная часть логики должна быть реализована в этом типе и некоторые отдельные детали должны быть указаны в производном классе / классе реализации, используйте абстрактный класс. Если тип только указывает, как к нему можно получить доступ, а реализованные методы просто удобны для класса реализации, например, преобразование аргумента из альтернативного типа в в основном реализованный тип, используйте интерфейс с реализациями по умолчанию.