C# Diamond-Inheritance(接口实现)
C# Diamond-Inheritance (Interface Implementation)
如果 class 从两个单独的接口实现一个接口,它的行为是否就像只实现一次一样?
示例:
public interface IAnimal { /* ... */ }
public interface IFullAnimal : IAnimal { /* ... */ }
public interface IBear : IAnimal { /* ... */ }
public interface IFullBear : IBear, IFullAnimal { /* ... */ }
// and implementing IFullBear:
public class FullBear : IFullBear { /* ... */ }
上面,FullBear
从 IFullAnimal
和 IBear
到 IFullBear
实现了 IAnimal
。这是否引入了任何关于 IAnimal 实现的奇怪行为,因为 IFullAnimal
和 IBear
都没有提供任何关于 IAnimal
实现的信息(因为语言不允许这样做)。
在 .NET 中,如果 IA
和 IB
都继承自 IX
并且 class 实现了两者,则 [=30 的成员之间没有区别=] 和 "the IX
inherited by IB
" 的那些。所有这些成员都只是 IX
的成员。此外,声明为实现 IA
、IB
和 IX
的 class 与仅声明为实现 [=10= 的 class 之间没有区别] 和 IB
,因为任何实现 IA
、IB
或两者的 class 也必然会实现 IX
,无论它是否被声明为 doing所以。
接口继承的 .NET 模型避免了 "diamond problem",因为中级接口不能向继承的接口添加任何东西,以将它们与那些相同接口的任何其他继承版本区分开来。 Java 的模型过去也避免了菱形问题,但是通过允许中级接口声明默认方法,Java 的更高版本使致命的菱形层次结构成为可能。
不会,这是一种非常常见且无害的情况。 System.Collections.Generic
命名空间是类似 "redundant" 接口声明的一个很好的例子:
public class List<T> : IList<T>,
System.Collections.IList,
IReadOnlyList<T>
IList<T>
和 IReadOnlyList<T>
显然都实现了 IEnumerable<T>
,世界还没有结束。
不要将此与 接口重新实现 混淆,后者确实会改变行为:
interface IFoo
{
void Foo();
}
class Base: IFoo
{
public void Foo() { Console.WriteLine("Base Foo!");
}
class Derived: Base { }
class DerivedWithATwist: Base, IFoo //redeclares interface
{
void IFoo.Foo() { Console.WriteLine("Derived Foo!");
}
现在,
IFoo foo = new Base();
IFoo derived = new Derived();
IFoo derivedWithATwist = new DerivedWithATwist();
foo.Foo(); //Base Foo!
derived.Foo(); //Base Foo!
derivedWithATwist.Foo(); //Derived Foo!
(derivedWithATwist as Base).Foo(); //Base Foo! !!!
如果 class 从两个单独的接口实现一个接口,它的行为是否就像只实现一次一样?
示例:
public interface IAnimal { /* ... */ }
public interface IFullAnimal : IAnimal { /* ... */ }
public interface IBear : IAnimal { /* ... */ }
public interface IFullBear : IBear, IFullAnimal { /* ... */ }
// and implementing IFullBear:
public class FullBear : IFullBear { /* ... */ }
上面,FullBear
从 IFullAnimal
和 IBear
到 IFullBear
实现了 IAnimal
。这是否引入了任何关于 IAnimal 实现的奇怪行为,因为 IFullAnimal
和 IBear
都没有提供任何关于 IAnimal
实现的信息(因为语言不允许这样做)。
在 .NET 中,如果 IA
和 IB
都继承自 IX
并且 class 实现了两者,则 [=30 的成员之间没有区别=] 和 "the IX
inherited by IB
" 的那些。所有这些成员都只是 IX
的成员。此外,声明为实现 IA
、IB
和 IX
的 class 与仅声明为实现 [=10= 的 class 之间没有区别] 和 IB
,因为任何实现 IA
、IB
或两者的 class 也必然会实现 IX
,无论它是否被声明为 doing所以。
接口继承的 .NET 模型避免了 "diamond problem",因为中级接口不能向继承的接口添加任何东西,以将它们与那些相同接口的任何其他继承版本区分开来。 Java 的模型过去也避免了菱形问题,但是通过允许中级接口声明默认方法,Java 的更高版本使致命的菱形层次结构成为可能。
不会,这是一种非常常见且无害的情况。 System.Collections.Generic
命名空间是类似 "redundant" 接口声明的一个很好的例子:
public class List<T> : IList<T>,
System.Collections.IList,
IReadOnlyList<T>
IList<T>
和 IReadOnlyList<T>
显然都实现了 IEnumerable<T>
,世界还没有结束。
不要将此与 接口重新实现 混淆,后者确实会改变行为:
interface IFoo
{
void Foo();
}
class Base: IFoo
{
public void Foo() { Console.WriteLine("Base Foo!");
}
class Derived: Base { }
class DerivedWithATwist: Base, IFoo //redeclares interface
{
void IFoo.Foo() { Console.WriteLine("Derived Foo!");
}
现在,
IFoo foo = new Base();
IFoo derived = new Derived();
IFoo derivedWithATwist = new DerivedWithATwist();
foo.Foo(); //Base Foo!
derived.Foo(); //Base Foo!
derivedWithATwist.Foo(); //Derived Foo!
(derivedWithATwist as Base).Foo(); //Base Foo! !!!