C#应该有多重继承吗?
我遇到过许多反对在C#中包含多重继承的论点,其中一些包括(哲学论点除外):C#应该有多重继承吗?,c#,inheritance,multiple-inheritance,C#,Inheritance,Multiple Inheritance,我遇到过许多反对在C#中包含多重继承的论点,其中一些包括(哲学论点除外): 多重继承太复杂,而且常常模棱两可 这是不必要的,因为接口提供了类似的功能 当接口不合适时,组合是一个很好的替代品 我来自C++背景,错过了多重继承的力量和优雅。虽然它不适合所有的软件设计,但在某些情况下,很难否认它在接口、组合和类似OO技术上的实用性 排除多重继承是否意味着开发人员不够聪明,无法明智地使用它们,并且无法解决出现的复杂性 我个人很欢迎将多重继承引入C#(也许是C#) 附录:我想从回答中了解哪些人来自单
- 多重继承太复杂,而且常常模棱两可
- 这是不必要的,因为接口提供了类似的功能
- 当接口不合适时,组合是一个很好的替代品
附录:我想从回答中了解哪些人来自单一(或程序背景)或多重继承背景。我经常发现,没有多重继承经验的开发人员通常会默认多重继承是不必要的论点,因为他们没有任何范例经验。我从来没有错过过一次,从来没有。是的,它(MI)变得复杂,是的,接口在许多方面做着类似的工作——但这不是最重要的一点:在一般意义上,大多数时候根本不需要它。在许多情况下,即使是单一继承也会被过度使用。我认为如果没有提供足够的ROI,它会使事情变得过于复杂。我们已经看到人们用太深的继承树来屠杀.NET代码。我可以想象,如果人们有权继承多重遗产,会发生什么样的暴行
我不否认它有潜力,但我只是没有看到足够的好处。C#支持单一继承、接口和扩展方法。在它们之间,它们提供了多重继承所提供的一切,而没有多重继承所带来的麻烦。我反对多重继承的理由仅仅是你所说的。开发者会滥用它。我已经看到了从实用程序类继承的每个类的足够多的问题,只是为了让您可以从每个类调用函数,而不需要太多的键入,知道多重继承在许多情况下都会导致错误代码。关于GoTo也可以说同样的话,这也是人们对它的使用如此不满的原因之一。我认为多重继承确实有一些很好的用途,就像GoTo一样,在一个理想的世界中,它们只有在适当的时候才被使用,不会有任何问题。然而,这个世界并不理想,所以我们必须保护糟糕的程序员不受他们自己的影响。虽然在某些情况下它确实是有用的,但我发现大多数时候,当我认为我需要它时,我真的不知道。自从C#首次作为alpha/beta版本发布以来,我就一直在使用它,而且从未错过过多重继承。MI在某些方面很好,但几乎总是有其他方法可以达到相同的结果(其中一些方法实际上更简单或创建更易于理解的实现)。更喜欢聚合而不是继承
class foo : bar, baz
通常处理得更好
class foo : Ibarrable, Ibazzable
{
...
public Bar TheBar{ set }
public Baz TheBaz{ set }
public void BarFunction()
{
TheBar.doSomething();
}
public Thing BazFunction( object param )
{
return TheBaz.doSomethingComplex(param);
}
}
通过这种方式,您可以交换IBarrable和IBazzable的不同实现,以创建应用程序的多个版本,而无需编写另一个类
依赖注入对此有很大帮助。多重继承通常是有用的,许多OO语言以某种方式实现它(C++、Eiffel、CLOS、Python……)。这是必要的吗?不,有这么好吗?是。更新
我向每一个投票反对我的人提出挑战,让他们向我展示任何多重继承的例子,我不能轻易地将其移植到具有单一继承的语言。除非有人能出示任何这样的样品,否则我声称它是不存在的。我已经将大量的C++代码(MH)移植到java(没有MH),这从来都不是问题,不管C++代码使用了多少MH。
到目前为止,没有人能够证明多重继承比您在文章中提到的其他技术更有效(使用接口和委托,我可以在没有太多代码或开销的情况下获得完全相同的结果),但它有几个众所周知的缺点(最令人讨厌的缺点) 实际上,多重继承通常被滥用。如果您使用OO设计以某种方式将真实世界建模为类,您将永远无法达到多重继承真正有意义的程度。你能为多重继承提供一个有用的例子吗?到目前为止,我看到的大多数例子实际上都是“错误的”。它们使某些东西成为子类,实际上只是一个额外的属性,因此实际上是一个接口
看一看。它是一种编程语言,接口确实有多重继承,为什么不呢(它不会产生菱形问题),但是没有接口的类没有继承。它们只能实现接口,并且可以“包含”其他对象,这使这些其他对象成为它们的固定部分,但这与继承不同,它是一种委托形式(通过包含对象而“继承”的方法调用实际上只是转发到封装在对象中的这些对象的实例)。我认为这个概念非常有趣,它表明你可以拥有一个完全干净的OO语言,而不需要任何实现继承。一位同事写了这个博客,讲述了如何通过动态编译在C#中获得类似多重继承的东西: 否。
(投票)我认为这很简单。就像任何其他复杂的编程范例一样,您可能会误用它并伤害自己。你可以误用对象(哦,是的!),但这并不意味着OO本身就是坏的
/// This trait declares default methods of IList<T>
public trait DefaultListMethods<T> : IList<T>
{
// Methods without bodies must be implemented by another
// trait or by the class
public void Insert(int index, T item);
public void RemoveAt(int index);
public T this[int index] { get; set; }
public int Count { get; }
public int IndexOf(T item)
{
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = 0; i < Count; i++)
if (comparer.Equals(this[i], item))
return i;
return -1;
}
public void Add(T item)
{
Insert(Count, item);
}
public void Clear()
{ // Note: the class would be allowed to override the trait
// with a better implementation, or select an
// implementation from a different trait.
for (int i = Count - 1; i >= 0; i--)
RemoveAt(i);
}
public bool Contains(T item)
{
return IndexOf(item) != -1;
}
public void CopyTo(T[] array, int arrayIndex)
{
foreach (T item in this)
array[arrayIndex++] = item;
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
int i = IndexOf(item);
if (i == -1)
return false;
RemoveAt(i);
return true;
}
System.Collections.IEnumerator
System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < Count; i++)
yield return this[i];
}
}
class MyList<T> : MyBaseClass, DefaultListMethods<T>
{
public void Insert(int index, T item) { ... }
public void RemoveAt(int index) { ... }
public T this[int index] {
get { ... }
set { ... }
}
public int Count {
get { ... }
}
}
abstract class Gun
{
public void Shoot(object target) {}
public void Shoot() {}
public abstract void Reload();
public void Cock() { Console.Write("Gun cocked."); }
}
class Camera
{
public void Shoot(object subject) {}
public virtual void Reload() {}
public virtual void Focus() {}
}
//this is great for taking pictures of targets!
class PhotoPistol : Gun, Camera
{
public override void Reload() { Console.Write("Gun reloaded."); }
public override void Camera.Reload() { Console.Write("Camera reloaded."); }
public override void Focus() {}
}
var pp = new PhotoPistol();
Gun gun = pp;
Camera camera = pp;
pp.Shoot(); //Gun.Shoot()
pp.Reload(); //writes "Gun reloaded"
camera.Reload(); //writes "Camera reloaded"
pp.Cock(); //writes "Gun cocked."
camera.Cock(); //error: Camera.Cock() not found
((PhotoPistol) camera).Cock(); //writes "Gun cocked."
camera.Shoot(); //error: Camera.Shoot() not found
((PhotoPistol) camera).Shoot();//Gun.Shoot()
pp.Shoot(target); //Gun.Shoot(target)
camera.Shoot(target); //Camera.Shoot(target)
public class PhotoPistol : Gun /* ,Camera */
{
PhotoPistolCamera camera;
public PhotoPistol() {
camera = new PhotoPistolCamera();
}
public void Focus() { camera.Focus(); }
class PhotoPistolCamera : Camera
{
public override Focus() { }
}
public static Camera implicit operator(PhotoPistol p)
{
return p.camera;
}
}
interface I
{
void F();
void G();
}
class DefaultI : I
{
void F() { ... }
void G() { ... }
}
class C : I = DefaultI
{
public void F() { ... } // implements I.F
}