如何inheritance构造函数?

想象一下有许多构造函数和虚方法的基类

public class Foo { ... public Foo() {...} public Foo(int i) {...} ... public virtual void SomethingElse() {...} ... } 

现在我想创build一个覆盖虚拟方法的后代类:

 public class Bar : Foo { public override void SomethingElse() {...} } 

而另一个后裔,做更多的东西:

 public class Bah : Bar { public void DoMoreStuff() {...} } 

我真的不得不将Foo的所有构造函数复制到Bar和Bah中吗? 然后,如果我在Foo中更改构造函数签名,是否必须在Bar和Bah中更新它?

有没有办法inheritance构造函数? 有没有办法来鼓励代码重用?

是的,您必须实现对每个派生有意义的构造函数,然后使用base关键字将该构造函数指向相应的基类或this关键字,以将构造函数指向同一类中的另一个构造函数。

如果编译器对inheritance构造函数做了假设,我们将无法正确地确定我们的对象是如何实例化的。 大多数情况下,你应该考虑为什么你有这么多的构造函数,并且考虑把它们减less到基类中的一两个。 然后,派生类可以使用像null这样的常量值来屏蔽掉其中的一些,只通过构造函数暴露必要的类。

更新

在C#4中,您可以指定默认参数值并使用命名参数使单个构造器支持多个参数configuration,而不是每个configuration都具有一个构造器。

387构造函数 这是你的主要问题。 这个怎么样?

 public Foo(params int[] list) {...} 

是的,你必须复制全部387个构造函数。 你可以通过redirect来做一些重用:

  public Bar(int i): base(i) {} public Bar(int i, int j) : base(i, j) {} 

但这是你能做的最好的。

太糟糕了,我们不得不告诉编译器显而易见:

 Subclass(): base() {} Subclass(int x): base(x) {} Subclass(int x,y): base(x,y) {} 

我只需要在12个子类中做3个构造函数,所以没有什么大不了的,但我不太喜欢每个子类都习惯于不用写这么长时间。 我相信有一个合理的理由,但我不认为我遇到过需要这种限制的问题。

不要忘记,你也可以在相同的inheritance层次上将构造函数redirect到其他构造函数:

 public Bar(int i, int j) : this(i) { ... } ^^^^^ 

另一个简单的解决scheme可能是使用包含参数作为属性的结构或简单的数据类; 这样您可以提前设置所有的默认值和行为,将“参数类”作为单个构造参数传入:

 public class FooParams { public int Size... protected myCustomStruct _ReasonForLife ... } public class Foo { private FooParams _myParams; public Foo(FooParams myParams) { _myParams = myParams; } } 

这避免了多个构造函数的混乱(有时),并提供了强types,默认值和其他的好处,而不是由参数数组提供的。 由于从Fooinheritance的任何东西仍然可以根据需要到达,甚至添加到FooParams,所以它也使得inheritance变得容易。 你仍然需要复制构造函数,但是你总是(大多数情况下)(至less现在)(至less现在)只需要一个构造函数。

 public class Bar : Foo { public Bar(FooParams myParams) : base(myParams) {} } 

我真的很喜欢重载的Initailize()和Class Factory Pattern方法,但是有时候你只需要一个聪明的构造函数。 只是一个想法。

由于Foo是一个类,你可以不创build虚拟重载的Initialise()方法? 那么他们将可用于子类,仍然可扩展?

 public class Foo { ... public Foo() {...} public virtual void Initialise(int i) {...} public virtual void Initialise(int i, int i) {...} public virtual void Initialise(int i, int i, int i) {...} ... public virtual void Initialise(int i, int i, ..., int i) {...} ... public virtual void SomethingElse() {...} ... } 

这应该不会有更高的性能成本,除非你有很多默认的属性值,你打了很多。

 public class BaseClass { public BaseClass(params int[] parameters) { } } public class ChildClass : BaseClass { public ChildClass(params int[] parameters) : base(parameters) { } } 

我个人认为这是微软部分的一个错误,他们应该允许程序员重写基类中构造函数,方法和属性的可见性,然后使得构造函数总是被inheritance。

这样,我们只是简单地覆盖(更低的可见性 – 即。私有)我们不想要的构造函数,而不必添加我们想要的所有构造函数。 delphi这样做,我想念它。

举个例子,如果你想覆盖System.IO.StreamWriter类,你需要添加所有7个构造函数到你的新类,如果你喜欢评论,你需要注释每个头XML。 更糟糕的是,元数据视图dosnt把XML注释作为正确的XML注释,所以我们必须一行一行地复制和粘贴它们。 微软在这里思考什么?

实际上,我写了一个小工具,可以粘贴元数据代码,并使用超级可见性将其转换为XML注释。

问题不在于Bar和Bah必须复制387个构造函数,问题是Foo有387个构造函数。 Foo显然做了太多事情 – 重构快! 另外,除非你有一个很好的理由在构造函数中设置值(如果你提供了一个无参数的构造函数,你可能不需要),我build议使用属性获取/设置。

我真的不得不将Foo所有构造函数复制到BarBah吗? 然后,如果我在Foo更改构造函数签名,是否必须在BarBah更新它?

是的,如果你使用构造函数来创build实例。

有没有办法inheritance构造函数?

不。

有没有办法来鼓励代码重用?

那么,我不会考虑inheritance构造函数是好还是坏,是否会鼓励代码重用,因为我们没有它们,我们也不会得到它们。 🙂

但是在2014年,使用当前的C#,通过使用通用的create方法,您可以获得非常inheritance构造函数的东西。 它可以是一个有用的工具,但你不能轻易达到。 我最近遇到了这个问题,当面临需要传递一些基types的构造函数的时候,这个基types在几百个派生类中使用(直到最近,基本不需要任何参数,所以默认的构造函数很好 – 派生类类没有声明构造函数,并获得了自动提供的)。

它看起来像这样:

 // In Foo: public T create<T>(int i) where: where T : Foo, new() { T obj = new T(); // Do whatever you would do with `i` in `Foo(i)` here, for instance, // if you save it as a data member; `obj.dataMember = i;` return obj; } 

这就是说,你可以使用一个types参数来调用通用的create函数,该types参数是具有零参数构造函数的Foo任何子types。

然后,而不是做Bar b new Bar(42) ,你会这样做:

 var b = Foo.create<Bar>(42); // or Bar b = Foo.create<Bar>(42); // or var b = Bar.create<Bar>(42); // But you still need the <Bar> bit // or Bar b = Bar.create<Bar>(42); 

在那里,我直接展示了create方法在Foo ,但是当然,如​​果它所设置的信息可以由工厂类来设置的话,它当然也可以在某种类的工厂类中。

只是为了清楚:名称create并不重要,它可以是makeThingy或其他任何你喜欢的。

完整的例子

 using System.IO; using System; class Program { static void Main() { Bar b1 = Foo.create<Bar>(42); b1.ShowDataMember("b1"); Bar b2 = Bar.create<Bar>(43); // Just to show `Foo.create` vs. `Bar.create` doesn't matter b2.ShowDataMember("b2"); } class Foo { public int DataMember { get; private set; } public static T create<T>(int i) where T: Foo, new() { T obj = new T(); obj.DataMember = i; return obj; } } class Bar : Foo { public void ShowDataMember(string prefix) { Console.WriteLine(prefix + ".DataMember = " + this.DataMember); } } } 

不,你不需要复制所有387个构造函数给Bar和Bah。 Bar和Bah可以像你想要的那样拥有尽可能多的构造函数,而与你在Foo上定义的数量无关。 例如,你可以select只有一个Bar构造函数,它用Foo的第212个构造函数构造Foo。

是的,您在Bar或Bah依赖的Foo中更改的构造函数将要求您相应地修改Bar和Bah。

不,.NET中没有办法inheritance构造函数。 但是,您可以通过在子类的构造函数中调用基类的构造函数或调用您定义的虚拟方法(如Initialize())来实现代码重用。

您可能可以修改C ++虚拟构造函数的一个版本。 据我所知,C#不支持协变返回types。 我相信这是在许多人的愿望清单。

太多的构造函数是破坏devise的标志。 更好的一个类与几个构造函数和设置属性的能力。 如果您确实需要控制属性,请考虑使用相同名称空间的工厂,并将属性设置器设置为内部。 让工厂决定如何实例化类并设置其属性。 工厂可以根据需要采取尽可能多的参数来正确configuration对象。