2010-02-13 2 views
7

Я хотел бы добиться этого в C#C# множественное наследование

(псевдокод)

class A; 

class B : A; 

class C : A, B; 

... 

A ac = (A)c; 

... 

B bc = (B)c; 

Возможно ли это?

+0

Нет, проверьте: http://stackoverflow.com/questions/191691/ http://stackoverflow.com/questions/995255/ –

+0

http://stackoverflow.com/questions/2846752/am-i -trying-to-implement-multiple-inheritance-how-can-i-do-this и http://stackoverflow.com/questions/2456154/does-c-support-multiple-inheritance – Russell

ответ

3

№ C# не поддерживает множественное наследование классов.

Класс может наследовать от одного класса и может также реализовывать несколько интерфейсов.

+0

@stakx: хороший улов. Исправленный. –

0

Вы можете использовать интерфейсы для множественного наследования.

2

В C# это невозможно, но вам также следует подумать, действительно ли это тот сценарий, который вы действительно хотите.

ЯвляетсяC действительно и B? Или Cимеет a A и a B. Если последнее верно, вы должны использовать композицию вместо наследования.

+0

Я не могу использовать композицию по некоторым причинам. Пробовал это. Проблема. Базовые классы используют делегаты и предоставляют ссылки на себя в обратном вызове. Если C включает A и B, обратные вызовы содержат ссылки на A и/или B, а не на C, как требуется. Это обеспечивается, если я наследую C от A и B. Интерфейсы - это опция, используйте ее уже. – neil

9

Вам не нужно множественное наследование в данном случае: если класс C наследует только от B, любой экземпляр класса C может быть брошено на оба BиA; поскольку B уже происходит от A, C не должен быть получен из A снова:

class A  { ... } 

class B : A { ... } 

class C : B { ... } 

... 

C c = new C(); 
B bc = (B)c; // <-- will work just fine without multiple inheritance 
A ac = (A)c; // <-- ditto 

(Как и другие уже сказал, если вам нужно что-то похожее на множественное наследование, использование интерфейсов, так как класс может реализовать как многие из них, как вы хотите.)

+0

Аргх ... Я наблюдал за очевидным. Спасибо за подсказку! С уважением – neil

+0

Хммм. Остается одна проблема: я не могу заставить C вести себя как A. B усиливает A и больше не предоставляет простые функциональные возможности (по мере необходимости). Проще говоря, мне нужен C, который иногда ведет себя как A, а иногда и B, в зависимости от контекста. – neil

+0

'C' должен вести себя как' A', если вы получите доступ к нему через 'ac'; Аналогично, 'C' должен вести себя как' B', если вы получите доступ к нему через 'bc'. Конечно, если у вас есть виртуальные методы, во всех этих случаях будут вызываться переопределенные версии. – stakx

0

C# не поддерживает множественное наследование, но, как предложили другие, вы можете использовать несколько интерфейсов. Однако даже с интерфейсами иногда вы хотите повторно использовать несколько реализаций интерфейса в одном классе, что опять-таки потребует многократного наследования.

Чтобы обойти это (хотя это почти never needed), я придумал метод имитации множественного наследования с использованием комбинации partial classes и T4 Text Templates. Это небольшой взлом, но это лучше, чем копировать/вставлять одну и ту же реализацию интерфейса во многих производных классах. Ниже приведен упрощенный пример:

IInterface.cs

public interface IInterface 
{ 
    void Foo(); 
} 

InterfaceImpl.cs

public partial class InterfaceImpl : IInterface 
{ 
    public void Foo() 
    { 
     Console.WriteLine("Foo"); 
    } 
} 

BaseClass.cs

using System; 

public class BaseClass 
{ 
    public void Bar() 
    { 
     Console.WriteLine("Bar"); 
    } 
} 

DerivedClassA.cs

public partial class DerivedClassA : BaseClass, IInterface 
{ 
    public void FooBar() 
    { 
     this.Foo(); 
     this.Bar(); 
    } 
} 

DerivedClassAInterfaceImpl.тт

<#@ template debug="false" hostspecific="true" language="C#" #> 
<#@ output extension=".cs" #> 
<# var codeText = System.IO.File.ReadAllText(this.Host.ResolvePath("InterfaceImpl.cs")).Replace("InterfaceImpl", "DerivedClassA"); #> 
<#= codeText #> 

DerivedClassB.cs

public partial class DerivedClassB : BaseClass, IInterface 
    { 
     public void BarFoo() 
     { 
      this.Bar(); 
      this.Foo(); 
     } 
    } 

DerivedClassBInterfaceImpl.tt

<#@ template debug="false" hostspecific="true" language="C#" #> 
<#@ output extension=".cs" #> 
<# var codeText = System.IO.File.ReadAllText(this.Host.ResolvePath("InterfaceImpl.cs")).Replace("InterfaceImpl", "DerivedClassB"); #> 
<#= codeText #> 

Это немного раздражает, что это требует создания файла Tt для каждого производного класса, который хочет использовать реализацию интерфейса , но он сохраняет код копирования/вставки, если InterfaceImpl.cs - это несколько строк кода. Также возможно, возможно, просто создать один файл tt и указать имя всех производных частичных классов и сгенерировать multiple files.

Я упомянул об этом подходе в аналогичном вопросе here.