C# 中的构造函数链

Fil Zjazel Romaeus Villegas 2023年10月12日
  1. 什么是构造函数
  2. 什么是构造函数重载
  3. 什么是构造函数链
  4. 构造函数链接示例
C# 中的构造函数链

本教程将演示如何在 C# 中进行构造函数链接。要了解构造函数链,首先必须了解以下概念。

什么是构造函数

构造函数是类中的一种方法,在创建对象时会自动执行。构造函数可以留空,也可以包含创建新实例时将遵循的各种说明和步骤。

参考下面的这个示例类。此类的构造函数将自动设置其变量的值,如下面的初始化详述。如果你将构造函数留空,则默认情况下所有类变量都将为 null

class Tutorial_Class {
  public string name;
  public DateTime created_date;
  public List<string> topics;
  public string description;
  public bool draft;

  public Tutorial_Class() {
    // This is the constructor method
    this.name = "Tutorial Draft";
    this.created_date = DateTime.Now;
    this.topics = new List<string>();
    this.description = "Tutorial Description";
    this.draft = false;
  }
}

什么是构造函数重载

构造函数重载允许你根据在创建类的新实例时提供的输入参数调用不同的构造函数。对于每个接受的参数场景,你必须定义要使用的构造函数。你可以拥有任意数量的构造函数重载。

在下面的示例中,我们添加了另一个接受单个字符串输入的构造函数。如果提供了输入,它会将 name 变量设置为输入值的变量。

class Tutorial_Class {
  public string name;
  public DateTime created_date;
  public List<string> topics;
  public string description;
  public bool draft;

  public Tutorial_Class() {
    // This is the initial constructor method and will be used if no parameter is passed
    this.name = "Tutorial Draft";
    this.created_date = DateTime.Now;
    this.topics = new List<string>();
    this.description = "Tutorial Description";
    this.draft = false;
  }

  public Tutorial_Class(string name) {
    // This is the second constructor method and will be used if you pass a single string parameter
    // Instead of the name variable being set to "Tutorial Draft", it will be set to the value of
    // the input parameter
    this.name = name;
    this.created_date = DateTime.Now;
    this.topics = new List<string>();
    this.description = "Tutorial Description";
    this.draft = false;
  }
}

什么是构造函数链

构造函数链接允许你从另一个构造函数中调用另一个构造函数。使用相同的示例,假设你在不传递任何参数的情况下创建了一个 Tutorial_Class 的新实例。我们可以修改初始构造函数,使其具有一个默认参数,该参数将触发第二个构造函数被调用。因此得名构造函数链。你也可以将其视为类似于可选参数,无论你是否显式传递任何内容,它都会设置默认值。

在下面的示例中,我们没有在初始构造函数中设置值,而是将默认名称 Tutorial Draft 传递给触发第二个构造函数的构造函数。

class Tutorial_Class {
  public string name;
  public DateTime created_date;
  public List<string> topics;
  public string description;
  public bool draft;

  public Tutorial_Class() : this("Tutorial Draft") {
    // The intiial constructor is now blank but will trigger the second constructor due to the
    // "this("Tutorial Draft")" line.
    // If you remove the parameter, all of the class variables will again be null by default instead
  }

  public Tutorial_Class(string name) {
    // As the initial constructor passed a single string parameter, this constructor is then called
    // and all variable values are set
    this.name = name;
    this.created_date = DateTime.Now;
    this.topics = new List<string>();
    this.description = "Tutorial Description";
    this.draft = false;
  }
}

构造函数链接示例

使用上面讨论的概念,我们可以应用构造函数链接并查看类的行为取决于不同的输入。

例子:

using System;
using System.Collections.Generic;

namespace ConstructorChaining_Example {
  class Program {
    static void Main(string[] args) {
      // Initialize a new instance of the class with no parameters
      Tutorial_Class no_params = new Tutorial_Class();
      // Print the results to the console
      Console.WriteLine("Tutorial_Class with No Parameters:\n");
      PrintVariables(no_params);

      // Initialize a new instance of the class with the tutorial name "Sample Tutorial 1"
      Tutorial_Class string_param = new Tutorial_Class("Sample Tutorial 1");
      // Print the results to the console
      Console.WriteLine("Tutorial_Class with a Tutorial Name Provided:\n");
      PrintVariables(string_param);

      // Initialize a new instance of the class with the tutorial name "Sample Tutorial 2" and a
      // created date of December 31, 2021.
      Tutorial_Class string_and_date_param =
          new Tutorial_Class("Sample Tutorial 2", new DateTime(2021, 12, 31));
      // Print the results to the console
      Console.WriteLine("Tutorial_Class with a Tutorial Name and Created Date Provided:\n");
      PrintVariables(string_and_date_param);

      Console.ReadLine();
    }

    public class Tutorial_Class {
      public string name;
      public DateTime created_date;
      public List<string> topics;
      public string description;
      public bool draft;

      public Tutorial_Class() : this("Tutorial Draft") {
        // This is the initial constructor class which is only executed when no parameters are
        // passed Once the class is created, the second constructor class will be triggered with the
        // name parameter "Tutorial Draft"
        this.description = "No Parameter Passed";
      }

      public Tutorial_Class(string name) : this(name, DateTime.Now) {
        // This is the second constructor class
        // This can be called by two ways, either by initializing the class with no parameters or by
        // passing a specific string parameter for the tutorial name Regardless of how this
        // constructor is triggered, it will by default also execute the third constructor class by
        // passing the current DateTime as the date param
        this.description = "A tutorial name has been passed";
      }

      public Tutorial_Class(string name, DateTime date) {
        // This is the third constructor class
        // Regardless of how the class is initialized, this will always be triggered due to how the
        // constructors are chained
        this.name = name;
        this.created_date = date;
        this.topics = new List<string>();
        this.description = "A tutorial name and created date have both been passed";
        this.draft = false;
      }
    }

    public static void PrintVariables(Tutorial_Class tutorial) {
      // This function accepts a Tutorial_Class and prints three of its variables to the console
      Console.WriteLine("Tutorial Name: " + tutorial.name + "\n");
      Console.WriteLine("Created Date: " + tutorial.created_date.ToString() + "\n");
      Console.WriteLine("Description: " + tutorial.description + "\n");

      Console.WriteLine("\n");
    }
  }
}

在上面的示例中,我们创建了 Tutorial_Class 的三个实例,并为每个实例提供了不同的参数。你可以观察到,无论哪个构造函数先初始化,它们总是触发第三个构造函数,这可以通过查看其他变量如何具有值来验证,而不仅仅是描述。

另一个需要注意的重要事情是,在执行其主构造函数中的指令之前,首先调用链式构造函数。这可以通过描述变量看到,该变量根据最初提供的参数而有所不同。

输出:

Tutorial_Class with No Parameters:

Tutorial Name: Tutorial Draft

Created Date: 28/12/2021 8:25:35 pm

Description: No Parameter Passed



Tutorial_Class with a Tutorial Name Provided:

Tutorial Name: Sample Tutorial 1

Created Date: 28/12/2021 8:25:35 pm

Description: A tutorial name has been passed



Tutorial_Class with a Tutorial Name and Created Date Provided:

Tutorial Name: Sample Tutorial 2

Created Date: 31/12/2021 12:00:00 am

Description: A tutorial name and created date have both been passed