C#中的多重inheritance

由于多重inheritance是不好的(这使得源代码更复杂),C#不直接提供这样的模式。 但是有时候有这个能力会有帮助。

例如,我能够使用接口和三个类来实现丢失的多重inheritance模式:

public interface IFirst { void FirstMethod(); } public interface ISecond { void SecondMethod(); } public class First:IFirst { public void FirstMethod() { Console.WriteLine("First"); } } public class Second:ISecond { public void SecondMethod() { Console.WriteLine("Second"); } } public class FirstAndSecond: IFirst, ISecond { First first = new First(); Second second = new Second(); public void FirstMethod() { first.FirstMethod(); } public void SecondMethod() { second.SecondMethod(); } } 

每次我添加一个方法的接口之一,我需要改变类FirstAndSecond以及。

有没有办法将多个现有的类注入到一个新的类中,就像使用C ++一样?

也许有一种使用某种代码生成的解决scheme?

或者它可能看起来像这样(虚构的c#语法):

 public class FirstAndSecond: IFirst from First, ISecond from Second { } 

因此,当我修改其中一个接口时,不需要更新FirstAndSecond类。


编辑

也许最好考虑一个实际的例子:

您有一个现有的类(例如基于ITextTcpClient的基于文本的TCP客户端),您已经在项目中的不同位置使用该类。 现在你觉得需要创build一个你的类的组件,以方便Windows窗体开发人员访问。

据我所知,你目前有两种方法来做到这一点:

  1. 编写一个从组件inheritance的新类,并使用FirstAndSecond所示的类本身实例来实现TextTcpClient类的接口。

  2. 写一个从TextTcpClientinheritance并以某种方式实现IComponent的新类(实际上还没有尝试过)。

在这两种情况下,你都需要按照方法而不是每个class级进行工作。 既然您知道我们将需要TextTcpClient和Component的所有方法,那么将这两个方法合并到一个类中将是最简单的解决scheme。

为了避免冲突,这可以通过代码生成来完成,其中结果可以在之后被改变,但是手工input是纯粹的屁股疼痛。

由于多重inheritance是不好的(这使得源代码更复杂),C#不直接提供这样的模式。 但是有时候有这个能力会有帮助。

C#和.net CLR还没有实现MI,因为他们还没有断定它将如何在C#,VB.net和其他语言之间进行互操作,这不是因为“它会使源更复杂”

MI是一个有用的概念,没有回答的问题是这样的:“当你在不同的超类中有多个共同的基类时,你做什么?

Perl是我工作过的唯一一个在MI工作和运行良好的语言。 .net可能有一天会介绍它,但还没有,CLR已经支持MI,但正如我所说,除此之外,还没有任何语言结构。

在此之前,你被代理对象和多个接口卡住:(

考虑只使用组合而不是试图模拟多重inheritance。 您可以使用接口来定义构成组成的类,例如: ISteerable指的是一个SteeringWheeltypes的属性, IBrakable意味着BrakePedaltypes的属性等。

完成之后,可以使用添加到C#3.0的扩展方法function来进一步简化这些隐含属性的调用方法,例如:

 public interface ISteerable { SteeringWheel wheel { get; set; } } public interface IBrakable { BrakePedal brake { get; set; } } public class Vehicle : ISteerable, IBrakable { public SteeringWheel wheel { get; set; } public BrakePedal brake { get; set; } public Vehicle() { wheel = new SteeringWheel(); brake = new BrakePedal(); } } public static class SteeringExtensions { public static void SteerLeft(this ISteerable vehicle) { vehicle.wheel.SteerLeft(); } } public static class BrakeExtensions { public static void Stop(this IBrakable vehicle) { vehicle.brake.ApplyUntilStop(); } } public class Main { Vehicle myCar = new Vehicle(); public void main() { myCar.SteerLeft(); myCar.Stop(); } } 

我也想这样 – 这就是我个人所说的混合,虽然我意识到这是一个超载的术语。 我希望能够指定用于实现接口的variables,可以select为特定的方法提供我自己的实现。

我已经更详细地对此进行了博客讨论,尽pipe在inheritance方面故意夸大其意味着什么。

我没有看到为什么在C#编译器中不能实现这个function的原因 – 但是这又是一个复杂的语言。

我创build了一个C#后编译器 ,使这种事情:

 using NRoles; public interface IFirst { void FirstMethod(); } public interface ISecond { void SecondMethod(); } public class RFirst : IFirst, Role { public void FirstMethod() { Console.WriteLine("First"); } } public class RSecond : ISecond, Role { public void SecondMethod() { Console.WriteLine("Second"); } } public class FirstAndSecond : Does<RFirst>, Does<RSecond> { } 

您可以将后编译器作为Visual Studio后构build事件运行:

C:\ some_path \ nroles-v0.1.0-bin \ nutate.exe“$(TargetPath)”

在同一个程序集中,你可以像这样使用它:

 var fas = new FirstAndSecond(); fas.As<RFirst>().FirstMethod(); fas.As<RSecond>().SecondMethod(); 

在另一个程序集中,你可以这样使用它:

 var fas = new FirstAndSecond(); fas.FirstMethod(); fas.SecondMethod(); 

你可以有一个实现了IFirst和ISecond的抽象基类,然后从那个基类inheritance。

MI不坏,大家有(认真)使用它,它并没有复杂的代码! 至less不会比其他结构更复杂的代码。 坏的代码是不好的代码,不pipeMI是否在图片中。

无论如何,我有一个很好的解决scheme,我想分享的多重inheritance,它在; http://ra-ajax.org/lsp-liskov-substitution-principle-to-be-or-not-to-be.blog或者你可以按照我的信号链接;… 🙂

如果你能忍受IFirst和ISecond的方法只能与IFirst和ISecond的合约交互的限制(就像在你的例子中那样)…你可以做你所要求的扩展方法。 实际上,情况很less。

 public interface IFirst {} public interface ISecond {} public class FirstAndSecond : IFirst, ISecond { } public static MultipleInheritenceExtensions { public static void First(this IFirst theFirst) { Console.WriteLine("First"); } public static void Second(this ISecond theSecond) { Console.WriteLine("Second"); } } 

///

 public void Test() { FirstAndSecond fas = new FirstAndSecond(); fas.First(); fas.Second(); } 

所以基本的想法是在接口中定义需要的实现…这个需要的东西应该支持扩展方法中的灵活实现。 任何时候你需要“添加方法到接口”,而不是你添加一个扩展方法。

是的使用接口是一个麻烦,因为任何时候我们在类中添加一个方法,我们必须在界面中添加签名。 另外,如果我们已经有一个类的方法,但没有接口呢? 我们必须手动为所有想要inheritance的类创build接口。 最糟糕的是,如果子类从多个接口inheritance,我们必须在子类的Interfaces中实现所有的方法。

通过遵循Facadedevise模式,我们可以模拟使用访问器从多个类inheritance。 在需要inheritance的类中声明类为{get; set;}的属性,并且所有公共属性和方法都来自该类,并且在子类的构造函数中实例化父类。

例如:

  namespace OOP { class Program { static void Main(string[] args) { Child somechild = new Child(); somechild.DoHomeWork(); somechild.CheckingAround(); Console.ReadLine(); } } public class Father { public Father() { } public void Work() { Console.WriteLine("working..."); } public void Moonlight() { Console.WriteLine("moonlighting..."); } } public class Mother { public Mother() { } public void Cook() { Console.WriteLine("cooking..."); } public void Clean() { Console.WriteLine("cleaning..."); } } public class Child { public Father MyFather { get; set; } public Mother MyMother { get; set; } public Child() { MyFather = new Father(); MyMother = new Mother(); } public void GoToSchool() { Console.WriteLine("go to school..."); } public void DoHomeWork() { Console.WriteLine("doing homework..."); } public void CheckingAround() { MyFather.Work(); MyMother.Cook(); } } } 

有了这个结构类Child就可以访问Class Father和Mother的所有方法和属性,模拟多重inheritance,inheritance父类的一个实例。 不完全相同,但它是实用的。

多重inheritance是通常导致比解决问题更多的问题之一。 在C ++中,它适合给你足够的绳子来吊起你自己的模式,但Java和C#已经select了更安全的路线,不给你select。 最大的问题是如果您inheritance多个具有与inheritance者不相同的签名的方法的类,该怎么做。 应该select哪一类的方法? 还是应该不编译? 通常还有另外一种方法来实现大多数不依赖于多重inheritance的东西。

如果X从Yinheritance,那有两个有点正交的作用:

  1. Y将为X提供默认的function,所以X的代码只需要包含与Y不同的东西。
  2. 几乎在任何地方Y是可以预期的,可以用X代替。

虽然inheritance既提供了这两种function,也不难想象在哪种情况下哪一种可以在没有其他function的情况下使用。 我知道没有.net语言有一个直接的方法来实现第一个没有第二个,虽然人们可以通过定义一个从未直接使用的基类,并有一个或多个类直接inheritance而不添加任何东西新的(这样的类可以共享他们所有的代码,但不会互相替代)。 但是,任何符合CLR的语言都将允许使用提供接口的第二个特性(可替代性)的接口,而不需要首先(成员重用)。

我知道我知道,即使它不允许,等等,有时你真的需要这样做的那些人:

 class a {} class b : a {} class c : b {} 

就像在我的情况下,我想要做这个类b:Form(是的Windows.forms)类c:b {}

导致一半的function是相同的,并与界面你必须重写它们

由于多重inheritance(MI)的问题不时出现,所以我想添加一个方法来解决组合模式中的一些问题。

我在这个问题中提出了FirstSecondFirstSecondFirstSecond方法。 我将示例代码减less到了IFirst ,因为无论接口/ MI基本类的数量如何,模式都保持不变。

让我们假设,MI FirstSecond都将从相同的基类BaseClass派生,只使用来自BaseClass公共接口元素

这可以通过在第FirstSecond实现中添加对BaseClass的容器引用来表示:

 class First : IFirst { private BaseClass ContainerInstance; First(BaseClass container) { ContainerInstance = container; } public void FirstMethod() { Console.WriteLine("First"); ContainerInstance.DoStuff(); } } ... 

事情变得更复杂,当引用来自BaseClass受保护的接口元素时,或者当FirstSecond将是MI中的抽象类时,要求它们的子类实现一些抽象部分。

 class BaseClass { protected void DoStuff(); } abstract class First : IFirst { public void FirstMethod() { DoStuff(); DoSubClassStuff(); } protected abstract void DoStuff(); // base class reference in MI protected abstract void DoSubClassStuff(); // sub class responsibility } 

C#允许嵌套类访问其包含的类的protected / private元素,所以可以使用它来链接First实现中的抽象位。

 class FirstAndSecond : BaseClass, IFirst, ISecond { // link interface private class PartFirst : First { private FirstAndSecond ContainerInstance; public PartFirst(FirstAndSecond container) { ContainerInstance = container; } // forwarded references to emulate access as it would be with MI protected override void DoStuff() { ContainerInstance.DoStuff(); } protected override void DoSubClassStuff() { ContainerInstance.DoSubClassStuff(); } } private IFirst partFirstInstance; // composition object public FirstMethod() { partFirstInstance.FirstMethod(); } // forwarded implementation public FirstAndSecond() { partFirstInstance = new PartFirst(this); // composition in constructor } // same stuff for Second //... // implementation of DoSubClassStuff private void DoSubClassStuff() { Console.WriteLine("Private method accessed"); } } 

这里涉及到很多样板,但是如果FirstMethod和SecondMethod的实际实现非常复杂,访问私有/受保护方法的数量适中,那么这种模式可能有助于克服缺乏多重inheritance的问题。

这是劳伦斯·温汉姆的答案,但取决于你的使用情况,这可能是也可能不是一个改进 – 你不需要setter。

 public interface IPerson { int GetAge(); string GetName(); } public interface IGetPerson { IPerson GetPerson(); } public static class IGetPersonAdditions { public static int GetAgeViaPerson(this IGetPerson getPerson) { // I prefer to have the "ViaPerson" in the name in case the object has another Age property. IPerson person = getPerson.GetPersion(); return person.GetAge(); } public static string GetNameViaPerson(this IGetPerson getPerson) { return getPerson.GetPerson().GetName(); } } public class Person: IPerson, IGetPerson { private int Age {get;set;} private string Name {get;set;} public IPerson GetPerson() { return this; } public int GetAge() { return Age; } public string GetName() { return Name; } } 

现在任何知道如何获得一个人的对象都可以实现IGetPerson,并且它将自动拥有GetAgeViaPerson()和GetNameViaPerson()方法。 从这一点来说,基本上所有的Person代码都进入了IGetPerson,而不是进入IPerson,除了新的Ivars之外,它们都必须进入到两者之中。 在使用这样的代码时,你不必关心你的IGetPerson对象本身是否是一个IPerson。

在C#中使用接口可以实现多重inheritance。可以用一个例子来解释 –

 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MultipleInheritApplication { interface calc1 { int add(int a, int b); } interface calc2 { int sub(int x, int y); } interface calc3 { int mul(int r, int s); } interface calc4 { int div(int c, int d); } class Calculation : calc1, calc2, calc3, calc4 { public int result1; public int add(int a, int b) { return result1 = a + b; } public int result2; public int sub(int x, int y) { return result2 = x - y; } public int result3; public int mul(int r, int s) { return result3 = r * s; } public int result4; public int div(int c, int d) { return result4 = c / d; } class Program { static void Main(string[] args) { Calculation c = new Calculation(); c.add(8, 2); c.sub(20, 10); c.mul(5, 2); c.div(20, 10); Console.WriteLine("Multiple Inheritance concept Using Interfaces :\n "); Console.WriteLine("Addition: " + c.result1); Console.WriteLine("Substraction: " + c.result2); Console.WriteLine("Multiplication :" + c.result3); Console.WriteLine("Division: " + c.result4); Console.ReadKey(); } } } } 

我们都似乎正在走这个接口path,但显而易见的其他可能性,在这里,是做OOP应该做的,并build立你的inheritance树…… (这不是什么类devise是所有关于?)

 class Program { static void Main(string[] args) { human me = new human(); me.legs = 2; me.lfType = "Human"; me.name = "Paul"; Console.WriteLine(me.name); } } public abstract class lifeform { public string lfType { get; set; } } public abstract class mammal : lifeform { public int legs { get; set; } } public class human : mammal { public string name { get; set; } } 

这个结构提供了可重用的代码块,当然,应该如何编写OOP代码?

如果这个方法不太适合我们,我们只需要根据所需的对象创build新的类…

 class Program { static void Main(string[] args) { fish shark = new fish(); shark.size = "large"; shark.lfType = "Fish"; shark.name = "Jaws"; Console.WriteLine(shark.name); human me = new human(); me.legs = 2; me.lfType = "Human"; me.name = "Paul"; Console.WriteLine(me.name); } } public abstract class lifeform { public string lfType { get; set; } } public abstract class mammal : lifeform { public int legs { get; set; } } public class human : mammal { public string name { get; set; } } public class aquatic : lifeform { public string size { get; set; } } public class fish : aquatic { public string name { get; set; } }