今天我碰巧发现一个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 :(得分:13)
实现接口的每个类在该类的成员和接口的成员之间都有映射。如果类显式实现了接口成员,那么显式实现将始终映射到接口。如果没有显式实现,则需要隐式实现,并且该实现将映射到接口。
当一个类具有相同的成员名称和相关类型作为接口但时,它还显式实现了接口的相应成员,那么该类的“隐式”实现不是< / em>被认为是接口的实现(除非显式实现调用它)。
除了在每种情况下类具有相同成员名称/类型的多个接口的不同含义之外,即使只有一个接口,类本身也被认为具有可能的隐式接口与唯一的界面具有相同的成员/类型,但仍然意味着不同的东西。
答案 1 :(得分:11)
您的示例不隐式和显式地实现IFoo。您只能显式实现IFoo.DoSometing()。您的类上有一个名为DoSomething()的新方法。它与IFoo.DoSomething无关,只是它具有相同的名称和参数。
答案 2 :(得分:7)
这使得它在发生碰撞时更加灵活。特别是,请查看IEnumerator
和IEnumerator<T>
- 它们都具有Current
属性,但属性不同。你有使用显式接口实现来实现它们(并且泛型形式扩展了非泛型形式)。
答案 3 :(得分: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();
}
}
答案 4 :(得分:0)
伙计们,谢谢你的回答。
事实证明“C#类可以同时以隐式和显式两种方式继承一个接口”实际上是一种错觉。实际上,一个类可以一次继承一个接口。
在最初的问题中,“DoSomething”方法似乎是“隐式实现”接口IFoo(该方法实际上是由VS2008生成的),但实际上并非如此。通过显式实现接口IFoo,“DoSomething”方法变成了普通的方法,除了具有相同的签名外,与IFoo无关。
我仍然认为它是一个棘手的C#设计,很容易误用它。说,我有一些像这样的代码
Foo f = new Foo();
f.DoSomething();
现在,我想将它重构为下面的代码。看起来完全没问题,但执行结果不同。
Action<IFoo> func = foo => foo.DoSomething();
func(f);