16

今天碰巧发现一个C#类可以隐式和显式地继承一个接口。这让我很惊讶。如果 C# 以这种方式工作,那么一个实例在以不同方式引用时可能表现不同。

interface IFoo
{
    void DoSomething();
}

class Foo : IFoo
{
    #region IFoo Members
    public void DoSomething()
    {
        Console.WriteLine("do something implicitly");
    }
    #endregion

    #region IFoo Members
    void IFoo.DoSomething()
    {
        Console.WriteLine("do something explicitly");
    }
    #endregion
}


        Foo f = new Foo();
        f.DoSomething();

        ((IFoo)f).DoSomething();

上面的代码运行并输出

do something implicitly
do something explicitly

我相信 C# 的这种设计会使行为不一致。一个 C# 类可能必须以隐式或显式方式从一个接口继承,但不能同时继承。

为什么 C# 以这种方式设计有什么原因吗?

4

5 回答 5

13

每个实现接口的类在该类的成员和接口的成员之间都有一个映射。如果类显式实现了接口成员,则显式实现将始终映射到接口。如果没有显式实现,则需要隐式实现,并且该实现将映射到接口。

当一个类具有与接口相同的成员名称和关联类型它也显式实现了接口的相应成员时,则该类的“隐式”实现根本不被视为接口的实现除非显式实现调用它)。

除了在类实现具有相同成员名称/类型的多个接口的每种情况下的不同含义之外,即使只有一个接口,该类本身也被认为具有一个隐式接口,该接口可能具有与唯一接口相同的成员/类型但仍然意味着不同的东西。

于 2008-10-31T10:28:49.693 回答
11

您的示例没有式和显式地实现 IFoo 。您只显式地实现 IFoo.DoSometing() 。您的类上有一个名为 DoSomething() 的新方法。它与 IFoo.DoSomething 无关,只是它具有相同的名称和参数。

于 2008-10-31T10:33:37.937 回答
7

这使得它在发生碰撞时更加灵活。特别是看IEnumeratorIEnumerator<T>- 它们都有一个Current属性,但类型不同。您必须使用显式接口实现才能实现两者(并且泛型形式扩展了非泛型形式)。

于 2008-10-31T10:30:33.310 回答
2

多重继承:如果您从两个定义相同方法的接口派生用于不同目的怎么办?

  interface IMoveable
  {
    public void Act();
  }

  interface IRollable
  {
    public void Act();
  }

  class Thing : IMoveable, IRollable
  {
    //TODO Roll/Move code here

    void IRollable.Act()
    {
      Roll();
    }

    void IMoveable.Act()
    {
      Move();
    }
  }
于 2008-10-31T10:29:48.273 回答
0

伙计们,谢谢你的回答。

事实证明,“C#类可以同时以隐式和显式方式继承一个接口”实际上是一种错觉。实际上,一个类可以继承一个接口一次。

在原始问题中,“DoSomething”方法似乎“隐式实现”接口IFoo(该方法实际上是由VS2008生成的),但实际上并非如此。通过接口 IFoo 的显式实现,“DoSomething”方法变成了与 IFoo 无关的普通方法,除了具有相同的签名。

我仍然认为它是 C# 的一个棘手的设计,而且很容易被误用。说,我有一些这样的代码

        Foo f = new Foo();
        f.DoSomething();

现在,我想将其重构为以下代码。看起来完全OK,但是执行结果不一样。

        Action<IFoo> func = foo => foo.DoSomething();
        func(f);
于 2008-10-31T11:19:34.927 回答