为什么这很重要:一个构造函数好,两个更好
您是否曾经编写过 C# 类,并注意到您有多个构造函数,它们做的事情几乎相同?例如,一个接受姓名和年龄,另一个只接受姓名,第三个什么都不接受。与其在每个构造函数中复制相同的代码,C# 提供了一个优雅的解决方案:从一个构造函数调用另一个构造函数。这不仅节省了时间——还使代码更简洁、更易理解、更易于维护。今天,我们将通过实际示例来探讨这个主题,就像您刚刚在 Stack Overflow 上发现了一个热门问题一样。开始吧!
如何在 C# 中从一个构造函数调用另一个构造函数
在 C# 中,您可以使用关键字 this 和 base 从一个构造函数调用另一个构造函数。这被称为“构造函数链”(constructor chaining)。让我们分析这两种情况。
1. 关键字 this —— 在同一类中调用构造函数
当您在同一个类中有多个构造函数时,您可以使用 this 将控制权传递给其中一个。当一个构造函数是另一个构造函数的“泛化”时,这尤其有用。
简单示例:一个存储姓名和年龄的 Person 类。默认构造函数设置标准值,而带参数的构造函数允许覆盖这些值。
public class Person{ public string Name { get; set; } public int Age { get; set; }
// 默认构造函数 public Person() : this("访客", 18) { // 这里什么都不写——一切由链式调用完成 }
// 带参数的构造函数 public Person(string name, int age) { Name = name; Age = age; }}在这段代码中,关键点是 : this("访客", 18)。当您通过 new Person() 创建对象时,会调用无参构造函数,但它立即将控制权传递给带两个参数的构造函数,并向其传递值“访客”和 18。这样,所有初始化逻辑都集中在一个地方。
2. 关键字 base —— 调用基类的构造函数
如果您的类继承自另一个类,您可以通过 base 调用基类的构造函数。这确保了对象的基类部分能被正确初始化。
示例:基类 Animal 和派生类 Dog。
public class Animal{ public string Species { get; set; }
public Animal(string species) { Species = species; }}
public class Dog : Animal{ public string Breed { get; set; }
// Dog 的构造函数调用 Animal 的构造函数 public Dog(string breed) : base("狗") { Breed = breed; }}这里的 : base("狗") 告诉编译器:“首先执行基类 Animal 的构造函数,参数为‘狗’,然后继续初始化 Dog”。如果没有这一行,您会收到编译错误,因为 Animal 没有默认构造函数。
实际示例:Stack Overflow 上的热门问题
想象一下,您正在开发一个在线商店的应用程序。您有一个 Order 类,它可以通过不同方式创建:使用客户 ID、使用完整数据集,或者根本不带参数(用于测试)。
public class Order{ public int OrderId { get; set; } public int CustomerId { get; set; } public decimal TotalAmount { get; set; } public DateTime CreatedDate { get; set; }
// 无参构造函数——用于测试 public Order() : this(0, 0, 0) { }
// 带最少数据的构造函数 public Order(int customerId, decimal totalAmount) : this(0, customerId, totalAmount)