为什么C#类可以隐式地和显式地从一个接口继承?

问题描述:

今天我碰巧发现一个C#类可以以隐式和显式方式继承一个接口。这让我感到惊讶。如果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#类可以以隐式或expliict方式从一个接口继承,但不能同时接受。

有什么理由说为什么C#是这样设计的?

+0

我没有注意到你可以同时做到这一点。这似乎有点傻... – 2008-10-31 10:26:41

+0

这并不傻。阅读答案。 – 2008-10-31 10:39:25

+0

对不起,我试图添加“显式接口成员实现”作为标签(这是你使用的功能的名称),但显然标签会太长。 :) – Rytmis 2008-10-31 11:11:03

您的示例确实不是隐式和显式实现IFoo。你只明确实现IFoo.DoSometing()。您的课堂上有一个名为DoSomething()的新方法。它与IFoo.DoSomething无关,只是它具有相同的名称和参数。

每个实现接口的类都有一个映射该类的成员和接口的成员之间。如果类明确地实现了接口成员,那么显式实现将总是被映射到接口。如果没有明确的实现,那么隐含的实现将被预期,并且那个将被映射到接口。

当一个类具有相同的会员名称和相关类型的接口它也明确实施相应的成员的接口,那么类的“隐性”的实施不是考虑到接口的实现根本不在(除非显式实现调用它)。

除了在将类实现具有相同的部件名称/类型的多个接口,即使只有一个接口每种情况下不同的含义,所述类本身被认为具有可能具有相同的构件的隐式接口/类型作为唯一的界面,但仍然意味着不同。

+0

这个隐式接口是一个实际的接口,还是仅仅暴露一个接口的类,即它是一种类型,尽管是一个隐藏的接口? – ProfK 2008-10-31 13:18:51

+0

我只是提到任何类的暴露。 CLR不会区分类的实现和其固有接口(即,除非接口是单独定义的接口类型,否则不能实现另一个类的接口并替换它)。 – 2008-10-31 16:20:33

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

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(); 
    } 
    } 

这使得它在碰撞时更加灵活。特别是,请看IEnumeratorIEnumerator<T> - 他们都有Current属性,但属于不同的类型。你有使用明确的接口实现为了实现两者(和通用形式扩展非通用形式)。

伙计们,谢谢你的回答。事实证明,“C#类可以同时以隐式和显式两种方式继承一个接口”实际上是一种错觉。实际上,一个类可以一次继承一个接口。

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

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

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

现在,我想重构它到下面的代码。看起来非常好,但执行结果不同。

 Action<IFoo> func = foo => foo.DoSomething(); 
     func(f);