为什么调用哪种接口方法很重要?

时间:2018-01-11 20:23:20

标签: c# oop interface explicit-interface

我正在研究接口,并且在某一点上我开始实现显式接口。在教程video at about 2:55中,它表示当一个类继承了两个不同的接口,并且如果这两个接口有一个具有相同名称的方法时,将会调用哪个接口的方法。

using System;

interface I1
{
    void InterfaceMethod();
}

interface I2
{
    void InterfaceMethod();
}

public class Program : I1, I2
{
    public void InterfaceMethod()
    {
        Console.WriteLine("I1 Interface Method");
    }

    public static void Main()
    {
        Program p = new Program();
        p.InterfaceMethod();
    }
}

我很困惑,因为接口没有方法定义,为什么调用哪个接口的方法很重要?两种方法都是相同的名称。

3 个答案:

答案 0 :(得分:2)

调用它很重要,因为尽管接口方法可能具有相同的名称(以及参数甚至返回类型),但它们在这些不同接口的上下文中可能具有完全不同的含义。因此,您必须能够指定每个接口使用哪种实现方法。

例如:

interface IVehicle
{
    int GetNumberOfWheels();
    int GetNumberOfDoors();
}

interface ICheeseContainer
{
    int GetNumberOfWheels();
    int GetNumberOfWedges();
}

class CheeseDeliveryTruck : IVehicle, ICheeseContainer
{
    // Object has to be able to return the number of wheels on the truck
    // when used as an IVehicle.

    // Object has to be able to return the number of cheeses in the back of
    // the truck which are packaged as wheels when used as an ICheeseContainer.
}

答案 1 :(得分:2)

  

为什么调用哪个接口的方法很重要?两种方法都是相同的名称。

也许那没关系。但也许不是。

在这种情况下,该方法的结果是输出“I1接口方法”,表明在实际代码中,等价物确实关注它是I1

当我们创建方法时,我们根据一个单词或几个单词在英语等自然语言中的含义,给出它们的名称,这些名称试图简洁明了。这可能导致两个具有相同名称的方法的目的实际上不同(无论是非常不同还是巧妙)。然后我们想要单独的实现。

当事情排成一行以便我们确实可以对两者使用相同的方法时,这很好,但是当我们不适合时,我们也不会被这种方法困住。

我们还拥有来为具有相同名称和参数签名但返回类型不同的方法的接口单独实现,因为C#无法区分这些。一个常见示例是IEnumerable<T>,因为它有GetEnumerator()方法返回IEnumerator<T>但继承自IEnumerable,其GetEnumerator()方法返回IEnumerator 。 (IEnumerator<T>IEnumerator也是同样原则的例子。)

我们可能希望进行显式接口实现的另一种情况是成员在具体类型的上下文中不是很有用。例如List<T>实现ICollection<T>。该接口具有IsReadOnly属性,在直接使用List<T>的上下文中毫无意义,因为我们知道它是错误的,因为List<T>本身不是只读的。当我们处理ICollection<T>引用时很重要(当然,规则要求它以某种方式实现),因此它是作为显式实现完成的。 ReadOnlyCollection<T>不仅做同样的事情(但当然是返回true而不是false),而且还会使像Add()这样的方法显然毫无意义,因为它们总会抛出无论如何,明确的例外。

答案 2 :(得分:1)

看起来你正在使用C#。所涉及的语言对于这个问题非常重要。当我提出这样的问题时,我会建议为此添加标签。

我认为C#将其视为模糊参考的原因,而不仅仅是对两者使用相同的实现,是

  1. 如果必须在实现类中声明这两个方法,那么具有相同名称的两个方法可以具有不同的返回类型,因此可以在更广泛的问题中使用相同的系统。

    interface I1 { 
        int Foo();
    }
    
    interface I2 {
        string Foo();
    }
    
    class C : I1, I2 {
        int I1.Foo() { ... }
    
        string I2.Foo() { ... }
    }
    
  2. 如果更新一个接口以更改参数,则使用该接口的代码将更容易更新,而不会破坏其他接口实现。