Ian*_*oyd 181 c# inheritance constructor
想象一下具有许多构造函数和虚方法的基类
public class Foo
{
...
public Foo() {...}
public Foo(int i) {...}
...
public virtual void SomethingElse() {...}
...
}
Run Code Online (Sandbox Code Playgroud)
现在我想创建一个覆盖虚方法的后代类:
public class Bar : Foo
{
public override void SomethingElse() {...}
}
Run Code Online (Sandbox Code Playgroud)
而另一个后代做了更多的东西:
public class Bah : Bar
{
public void DoMoreStuff() {...}
}
Run Code Online (Sandbox Code Playgroud)
我是否真的必须将所有构造函数从Foo复制到Bar和Bah?然后,如果我在Foo中更改构造函数签名,我是否必须在Bar和Bah中更新它?
有没有办法继承构造函数?有没有办法鼓励代码重用?
Jef*_*tes 122
是的,您必须实现对每个派生有意义的构造函数,然后使用该base关键字将该构造函数指向适当的基类或this关键字,以将构造函数指向同一个类中的另一个构造函数.
如果编译器对继承构造函数做出了假设,那么我们将无法正确确定对象的实例化方式.在大多数情况下,您应该考虑为什么您有这么多构造函数并考虑将它们减少到基类中的一个或两个.然后,派生类可以使用常量值来掩盖其中的一些,null并且仅通过其构造函数公开必要的值.
在C#4中,您可以指定默认参数值并使用命名参数使单个构造函数支持多个参数配置,而不是每个配置都有一个构造函数.
Kon*_*Kon 70
387个构造函数?? 那是你的主要问题.相反怎么样?
public Foo(params int[] list) {...}
Run Code Online (Sandbox Code Playgroud)
Jam*_*ran 42
是的,你必须复制所有387个构造函数.您可以通过重定向来重复使用它们:
public Bar(int i): base(i) {}
public Bar(int i, int j) : base(i, j) {}
Run Code Online (Sandbox Code Playgroud)
但那是你能做的最好的事情.
小智 34
太糟糕了,我们被迫告诉编译器显而易见:
Subclass(): base() {}
Subclass(int x): base(x) {}
Subclass(int x,y): base(x,y) {}
Run Code Online (Sandbox Code Playgroud)
我只需要在12个子类中做3个构造函数,所以这没什么大不了的,但我不太喜欢在每个子类上重复这个,因为我不习惯这么长时间写它.我确信这是有道理的,但我认为我从未遇到过需要这种限制的问题.
dvi*_*oen 27
不要忘记,您也可以在相同的继承级别将构造函数重定向到其他构造函数:
public Bar(int i, int j) : this(i) { ... }
^^^^^
Run Code Online (Sandbox Code Playgroud)
小智 10
另一个简单的解决方案可能是使用包含参数作为属性的结构或简单数据类; 这样你可以提前设置所有默认值和行为,将"参数类"作为单个构造函数参数传递:
public class FooParams
{
public int Size...
protected myCustomStruct _ReasonForLife ...
}
public class Foo
{
private FooParams _myParams;
public Foo(FooParams myParams)
{
_myParams = myParams;
}
}
Run Code Online (Sandbox Code Playgroud)
这避免了多个构造函数(有时)的混乱,并提供了强大的类型,默认值以及参数数组未提供的其他好处.它还可以很容易地继续发展,因为从Foo继承的任何内容仍然可以根据需要访问甚至添加到FooParams.你仍然需要复制构造函数,但是你总是(大部分时间)只(作为一般规则)(至少现在)需要一个构造函数.
public class Bar : Foo
{
public Bar(FooParams myParams) : base(myParams) {}
}
Run Code Online (Sandbox Code Playgroud)
我真的很喜欢重载的Initailize()和类工厂模式方法更好,但有时你只需要一个智能构造函数.只是一个想法.
作为Foo一个类,你能不能创建虚拟重载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() {...}
...
}
Run Code Online (Sandbox Code Playgroud)
除非你有很多默认属性值并且你经常遇到它,否则这应该没有更高的性能成本.
public class BaseClass
{
public BaseClass(params int[] parameters)
{
}
}
public class ChildClass : BaseClass
{
public ChildClass(params int[] parameters)
: base(parameters)
{
}
}
Run Code Online (Sandbox Code Playgroud)
我个人认为这在Microsofts部分是一个错误,它们应该允许程序员覆盖基类中的构造函数,方法和属性的可见性,然后使它成为总是继承构造函数.
这样我们只是简单地覆盖(具有较低的可见性 - 即私有)我们不想要的构造函数,而不必添加我们想要的所有构造函数.德尔福这样做,我想念它.
例如,如果要覆盖System.IO.StreamWriter类,则需要将所有7个构造函数添加到新类中,如果您想要注释,则需要使用标题XML对每个构造函数进行注释.更糟糕的是,元数据视图dosnt将XML注释作为正确的XML注释,因此我们必须逐行进行复制并粘贴它们.微软在这里想什么?
我实际上已经编写了一个小实用程序,您可以粘贴元数据代码,并使用过度可见性将其转换为XML注释.
我真的必须将所有构造函数从 in 复制
Foo到BarandBah吗?然后,如果我更改了构造函数签名Foo,是否必须在Bar和 中更新它Bah?
是的,如果您使用构造函数来创建实例。
有没有办法继承构造函数?
不。
有没有办法鼓励代码重用?
好吧,我不会讨论继承构造函数是好事还是坏事,以及它是否会鼓励代码重用,因为我们没有它们,我们也不会得到它们。:-)
但是在 2014 年,使用当前的 C#,您可以通过使用泛型方法来获得非常类似于继承构造函数的东西create。它可以成为您随身携带的有用工具,但您不会轻易伸手去拿它。我最近在面临需要将某些内容传递给数百个派生类中使用的基类型的构造函数时使用它(直到最近,基类不需要任何参数,因此默认构造函数很好 - 派生类类根本没有声明构造函数,而是获得了自动提供的构造函数)。
它看起来像这样:
// 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;
}
Run Code Online (Sandbox Code Playgroud)
也就是说,您可以create使用类型参数调用泛型函数,该类型参数是Foo具有零参数构造函数的任何子类型。
然后,而不是做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);
Run Code Online (Sandbox Code Playgroud)
在那里我已经展示了直接打开的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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
181040 次 |
| 最近记录: |