C# 在C中调用重写构造函数和基构造函数#
我有两个类,Foo和Bar,它们的构造函数如下:C# 在C中调用重写构造函数和基构造函数#,c#,constructor,C#,Constructor,我有两个类,Foo和Bar,它们的构造函数如下: class Foo { Foo() { // do some stuff } Foo(int arg) { // do some other stuff } } class Bar : Foo { Bar() : base() { // some third thing } } Bar(int arg) : Bar(), base(a
class Foo
{
Foo()
{
// do some stuff
}
Foo(int arg)
{
// do some other stuff
}
}
class Bar : Foo
{
Bar() : base()
{
// some third thing
}
}
Bar(int arg) : Bar(), base(arg)
{
// some fourth thing
}
现在我想为Bar引入一个构造函数,它接受一个int,但是我想让Bar()中发生的东西和Foo(int)中的东西一样运行。大概是这样的:
class Foo
{
Foo()
{
// do some stuff
}
Foo(int arg)
{
// do some other stuff
}
}
class Bar : Foo
{
Bar() : base()
{
// some third thing
}
}
Bar(int arg) : Bar(), base(arg)
{
// some fourth thing
}
在C#中有什么方法可以做到这一点吗?到目前为止,我最好的方法是将Bar()完成的工作放入一个函数中,该函数也会被Bar(int)调用,但这非常不雅观。你不能让接受int的Bar构造函数调用无参数构造函数吗?不,这是不可能的。如果您使用Reflector检查为每个构造函数生成的IL,您将看到原因——最终会为基类调用两个构造函数。理论上,编译器可以构造隐藏的方法来完成您想要的任务,但是与您显式地执行相同的任务相比,这并没有任何优势。您可以将Bar()中的内容放入Bar(int)中,并使用带有默认值的Bar()调用Bar(int)?然后Bar(int)可以调用基本构造函数
class Bar : Foo
{
Bar() : this(0)
{
}
Bar(int arg) : base(arg)
{
}
}
这并不能完全回答您的问题,但取决于您的场景,这可能是一个可行的解决方案。我将重新链接构造函数,因此它们被称为
Bar() : this(0)
Bar(int) : Foo(int) initializes Bar
Foo(int) initializes Foo
Foo() : this(0)
如果无参数构造函数为其他构造函数的int参数假定某种默认值,则这是合适的。如果构造函数是不相关的,那么您的类型可能有问题,或者我们需要更多关于您试图实现什么的信息。这是我唯一能想到的
public class Foo
{
public Foo()
{
}
public Foo(int? arg): this()
{
}
}
public class Bar : Foo
{
private int x;
public Bar(): this(new int?()) // edited to fix type ambiguity
{
// stuff that only runs for paramerless ctor
}
public Bar(int? arg)
: base(arg)
{
if (arg.HasValue)
{
// Do stuff for both parameterless and parameterized ctor
}
// Do other stuff for only parameterized ctor
}
}
我建议您将构造器链从最不特定改为最特定
class Foo
{
Foo()
{
// do some stuff
}
Foo(int arg): this()
{
// do some other stuff
}
}
class Bar : Foo
{
Bar() : Bar(0)
{
// some third thing
}
Bar(int arg): base(arg)
{
// something
}
}
Bar对象的任何创建现在都将调用所有4个构造函数。构造函数链接应该为更具体的构造函数提供默认值,而不是相反。你应该认真考虑你想要完成的事情,并确保你所做的是有意义的。Curt是对的,有技术上的原因你不能这样做,但也有逻辑上的原因你不能这样做。你能把Bar()的初始化代码变成一个方法并从两个构造函数调用它,让新的构造函数只调用base(arg)吗?你可以使用以下代码:
public Foo
{
public Foo()
{
this.InitializeObject();
}
public Foo(int arg) : this()
{
// do something with Foo's arg
}
protected virtual void InitializeObject()
{
// initialize object Foo
}
}
public Bar : Foo
{
public Bar : base() { }
public Bar(int arg) : base(arg)
{
// do something with Bar's arg
}
protected override void InitializeObject()
{
// initialize object Bar
base.InitializeObject();
}
}
只需像上面的代码一样重写InitializeObject()
方法,并将所有要放入无参数构造函数的代码放在那里。最后在代码末尾调用base.InitializeObject()
希望这是有用的。他还想调用基类的参数化构造函数。可以为null的想法有+1,但它有一些流程-如果添加另一个带有一个参数(类类型,而不是struct)的ctor,它将失败,就像现在这样(null)将不知道选择哪一个。可能是因为您没有给出问题的解决方案,即使问题显然存在。值得注意的是,虽然构造函数可以编写
只读
字段,但InitializeObject
方法将无法直接这样做。要在InitializeObject
方法中初始化此类字段,必须让构造函数将其作为ref
或out
参数传递(我更喜欢ref
,因为构造对象时字段值定义为空,而且我不喜欢虚拟方法上的out
参数,因为其他语言中的重写可能会将它们视为ref
参数)。您可以对只读字段执行此操作:专用只读字符串\u ro1=“只读1”;private readonly string _-ro2;private readonly int _-ro3;public Bar():base(){}public Bar(int-arg):base(arg){u-ro3=arg;_-ro2=“只读:”+arg;}
基本上,如果只读字段的值是由构造函数参数确定的,则可以将字段的初始化放在构造函数上。如果不是,则可以像上面的第一个只读字段一样进行初始化(\u ro1)。您的答案是建议将初始化代码从构造函数移到虚拟方法。可以在构造函数或字段初始值设定项中初始化只读字段,但也可以使用虚拟方法进行初始化,前提是将有问题的字段作为ref
或out
参数传递给有问题的方法。顺便说一句,一个我很想在vb.net和C#中看到,这是一种定义字段或伪字段的方法,该字段或伪字段将使用构造函数参数中的值进行初始化,并可在以后的字段初始化程序中使用其中(整数大小)
初始化ArrSize
将表明此类型的任何构造函数都将有一个名为Size
的int
参数,或者链接到一个名为Size
的参数,并且传递给该参数的值应用于初始化ArrSize
。在我看来,如果一个字段将被设置为一个可以e是基于构造函数参数计算的,以后再也没有修改过,将声明和初始化结合起来比在不同的地方写入更干净。