base() 和 this() 构造函数最佳实践
Posted
技术标签:
【中文标题】base() 和 this() 构造函数最佳实践【英文标题】:base() and this() constructors best practices 【发布时间】:2011-04-17 09:16:41 【问题描述】:在什么条件下我应该在构造函数的括号之后(甚至在代码中的其他位置)进行 :base()
和 :this()
构造函数调用。这些电话什么时候是好的做法,什么时候是强制性的?
【问题讨论】:
抱歉含糊不清......我知道这些电话在做什么。我只是不清楚我应该或必须拨打这些电话的情况。如果我不制作它们,那么我马上就注定要失败,或者会有潜在的错误,或者代码质量差。我最近很头疼,因此我想澄清这些情况。 —— 【参考方案1】:: base(...)
如果您省略对基构造函数的调用,它将自动调用默认基构造函数。
如果没有默认构造函数,则必须显式调用基本构造函数。
即使存在默认构造函数,您仍可能希望调用与默认构造函数不同的构造函数。在这种情况下,您可能仍希望使用base(foo, bar)
来调用与基本构造函数不同的构造函数。
我不认为当你想调用基类默认构造函数时省略base()
是一个坏习惯,尽管如果你想明确一点,我认为包含它并没有什么坏处。这是一个品味问题。
: this(...)
此语法允许您在同一类中调用具有不同签名的构造函数。这样做从来都不是强制性的,但有时会很有用。
一个有用的例子是在构造函数中重用公共代码。例如,在 C# 3.5 或之前,您可能希望在构造函数上模拟可选参数:
Foo(int x, int y)
this.x = x;
this.y = y;
Foo(int x) : this(x, 10) // y defaults to 10
现在可以使用 C# 4.0 可选参数,这减少了对这种方法的需求。
在构造函数中重用代码的另一种方法是将其分解为一个静态函数,该函数从每个希望使用它的构造函数中调用。
【讨论】:
【参考方案2】:首先,当它们是强制性的时。
当类Derived
派生自类Base
,并且Base
没有默认(无参数)构造函数时,Derived
必须显式调用base()
并带参数。
public class Base
public Base(int i)
public class Derived : Base
// public Derived() wouldn't work - what should be given for i?
public Derived() : base(7)
public Derived(int i) : base(i)
什么时候是好的做法?每当您想调用不同的构造函数时。
假设您在我之前的示例中将内容添加到 Derived 中的构造函数。
public class Derived : Base
// public Derived() wouldn't work - what should be given for i?
public Derived() : base(7)
Console.WriteLine("The value is " + 7);
public Derived(int i) : base(i)
Console.WriteLine("The value is " + i);
你注意到这里的重复了吗?调用 this() 构造函数更简单。
public class Derived : Base
// public Derived() wouldn't work - what should be given for i?
public Derived() : this(7)
public Derived(int i) : base(i)
Console.WriteLine("The value is " + i);
【讨论】:
所以最后一个例子中的调用顺序是:base(7)
,然后是Derived(7)
,然后是Derived()
。换句话说,this(7)
部分本身不会触发base()
(假设有这样的基本方法)。对吗?
正确;构造函数总是链式的,每个类都调用其基类的构造函数。使用this
,你可以重用这个类的另一个构造函数(它本身将使用base
,或者隐式地不带参数或显式地使用);使用base
,您可以选择调用哪个基类构造函数。【参考方案3】:
当存在继承时使用base
,并且父类已经提供了您想要实现的功能。
当您想要引用当前实体(或自身)时使用this
,当您不想复制已经在另一个构造函数中定义的功能时,在构造函数的标头/签名中使用它。
基本上,在构造函数的标头中使用 base 和 this 是为了让您的代码保持 DRY,使其更易于维护且不那么冗长
这是一个绝对没有意义的例子,但我认为它说明了展示如何使用这两者的想法。
class Person
public Person(string name)
Debug.WriteLine("My name is " + name);
class Employee : Person
public Employee(string name, string job)
: base(name)
Debug.WriteLine("I " + job + " for money.");
public Employee() : this("Jeff", "write code")
Debug.WriteLine("I like cake.");
用法:
var foo = new Person("ANaimi");
// output:
// My name is ANaimi
var bar = new Employee("ANaimi", "cook food");
// output:
// My name is ANaimi
// I cook food for money.
var baz = new Employee();
// output:
// My name is Jeff
// I write code for money.
// I like cake.
【讨论】:
【参考方案4】:查找“C# 中的构造函数链接”。基本上,它看起来像这样:
MyClass():base() //default constructor calling superclass constructor
MyClass(int arg):this() //non-basic constructor calling base constructor
//extra initialization
它有助于消除构造函数中的代码重复 - 将它们分成基本部分和特定部分。
【讨论】:
谢谢。 “构造函数链”这个词我不记得了。【参考方案5】:当您希望将基类的构造函数作为构造函数的第一条指令自动调用时,您可以使用 :base()。 :this() 类似,但它调用同一个类的另一个构造函数。
在 base:() 和 this() 中:您可以将常量值或基于构造函数参数的表达式作为参数传递。
当基类没有默认构造函数(不带参数的构造函数)时,必须调用基构造函数。我不知道 :this() 是强制性的。
public class ABaseClass
public ABaseClass(string s)
public class Foo : AChildClass
public AChildClass(string s) : base(s) //base mandatory
public AChildClass() : base("default value") //base mandatory
public AChildClass(string s,int i) : base(s+i) //base mandatory
public class AnotherBaseClass
public ABaseClass(string s)
public ABaseClass():this("default value") //call constructor above
public class Foo : AnotherChildClass
public AnotherChildClass(string s) : base(s) //base optional
【讨论】:
以上是关于base() 和 this() 构造函数最佳实践的主要内容,如果未能解决你的问题,请参考以下文章