1

我正在阅读这篇博客.NET Engineering Team他们为. 我对它的动机感到困惑,不是. 除此之外,我无法弄清楚任何其他好处。考虑以下代码:Interfaceabstract 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 classinterface都可以完成向其成员提供默认实现的相同工作。我对此有以下疑问:

  • 如果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?
}
4

1 回答 1

0

答:抽象类可以有字段和虚方法

这就是为什么 C# 不支持多重继承(Java 也是如此)

在以下情况下,具有多重继承的字段可能会导致问题:

class A : B, C {...}
class C : D {...}
class B : D {...}
class D
{
    ...
    protected int _value;
    ...
}

应该继承BC共享相同的实例_value吗?

两者都有原因。

B如果是这样,则和中的逻辑C可能会相互干扰,因为 的值_value既不可预测,B也不可预测C

而且B甚至C不知道它们会作为同一个对象的一部分相互协作。

如果不是,_value应该从哪个实例访问A

类似的问题也适用于虚拟方法。因为当两者都覆盖时,虚拟表将不再是线性的B并覆盖.CD

解决这些问题会使继承关系变得非常复杂,因此Java不支持多重继承,引入了接口的概念,C#也是如此。

界面如何解决这个问题

接口定义中只有方法声明(将属性作为访问器作为方法),因此不能有字段和方法覆盖。所以不存在多重继承问题。

C# 8.0 如何允许接口拥有方法体而不引起这些问题

C# 8.0 中的默认实现不使用与类继承逻辑中的虚拟表相同的逻辑,而是从最近的已实现接口中选择实现作为唯一可用实现的优先级机制,因此不存在虚拟表问题。

接口中仍然不允许有字段,因此不存在字段问题。

如何在具有默认实现的接口和抽象类之间进行选择

  • 从语法上讲,如果类型必须具有使用多个覆盖的字段或虚拟/抽象方法,则从继承树中的类型中,使用抽象类,否则使用接口。

  • 从逻辑上讲,如果逻辑的主要部分应该在这种类型中实现,并且要在派生/实现类中指定一些单个细节,请使用抽象类。如果类型只指定如何访问它并且实现的方法只是为实现类提供便利,例如将参数从替代类型转换为主要实现的类型,则使用具有默认实现的接口。

于 2019-09-25T05:24:28.680 回答