CodeGym /課程 /C# SELF /建構子與物件初始化

建構子與物件初始化

C# SELF
等級 16 , 課堂 3
開放

1. 簡單建構子

建構子 — 就是 class 裡一個特別的方法,在你 new 物件時會自動被呼叫。它會初始化(設定)物件:給初始值、做檢查,甚至你想寫個笑話讓你心情好也可以。

建構子讓你可以直接把物件生出來就有想要的狀態,不用一個一個 field 或 property 慢慢手動指定。這樣很方便又安全,因為你一開始就把重要參數都給好 — 不會忘記什麼超重要的東西。

沒有建構子的話,code 可能會很冗長又容易出錯:

Person p = new Person();
p.Name = "Юля";
p.Age = 25; // 如果忘記指定年齡會怎樣?

有建構子的話:


Person p = new Person("Юля", 25); // 一次給好,物件直接 ready to go!

建構子的語法

建構子就是一個特別的「方法」,名字要跟 class 名完全一樣,而且沒有回傳值(連 void 都不能有)。這是預設建構子的寫法:


public class Person
{
    // 預設建構子(沒參數)
    public Person()
    {
        // 這裡可以寫初始化的 code
    }
}
預設建構子

預設建構子就像一個隱形「小幫手」,不收任何參數,直接把 class 裡的 field 跟 property 都設成預設值:

  • 數字型別(intdoublefloat 等等)會是 0
  • 布林型別(bool)會是 false
  • 參考型別(string、其他 class)會是 null(就是「什麼都沒有」、「沒有指到物件」的意思)。
  • DateTime 會是 01.01.0001 00:00:00

怎麼呼叫建構子?

其實你在 new 物件時寫的 new,就是在呼叫建構子啦!

Person p = new Person();

如果你沒自己寫建構子,C# 編譯器會幫你生一個預設建構子(沒參數的那種)。但只要你自己寫了一個,預設建構子就不見了,編譯器會叫你自己加回來(如果你還需要的話)。

範例

來加個建構子到我們的應用程式 class。這是學生 class 的簡單版:


public class Student
{
    public string Name;
    public int Age;

    // 兩個參數的建構子(名字跟年齡)
    public Student(string name, int age)
    {
        Name = name; // 指定 field 的值
        Age = age;
    }
}

現在可以這樣生一個學生:

Student s = new Student("Иван", 21);
Console.WriteLine($"{s.Name}: {s.Age} 歲"); // Иван: 21 歲
  • 我們宣告的建構子 visibility(public)跟 class 一樣。
  • 建構子裡用傳進來的參數指定 field。
  • 這樣可以防止忘東忘西:編譯器會要求你 new 的時候一定要給名字跟年齡。

2. 建構子的參數

C# 可以宣告多個建構子,參數組合不一樣。這叫做建構子多載(method overload 之後還會講)。

比如加一個沒參數的建構子:

public class Student
{
    public string Name;
    public int Age;

    // 預設建構子
    public Student()
    {
        Name = "無名氏";
        Age = 0;
    }

    // 有參數的建構子
    public Student(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

現在兩種寫法都可以:


Student s1 = new Student();          // 名字:無名氏,年齡:0
Student s2 = new Student("Оля", 22); // 名字:Оля,年齡:22

用建構子做驗證

建構子超適合拿來檢查「輸入資料合不合理」。比如學生年齡不能是負的!


public Student(string name, int age)
{
    if (age < 0)
        throw new ArgumentException("年齡不能是負的!");
    Name = name;
    Age = age;
}

現在如果有人想 new 一個 Student("Малыш", -2),程式就會丟出例外(ArgumentException)。這種寫法很常見,讓資料超級可靠。

3. 複雜物件的初始化

實際應用裡,一個物件常常不只 primitive,也會包含其他物件:

public class Group
{
    public string GroupName;
    public Student[] Students;

    public Group(string groupName, Student[] students)
    {
        GroupName = groupName;
        Students = students;
    }
}

現在可以很簡單地生一個有學生陣列的 group:

var students = new Student[]
{
    new Student("Иван", 20),
    new Student("Мария", 19)
};
Group g = new Group("Группа-101", students);

Field 預設值初始化

有時候你會想給某些 field 預設值,如果建構子沒收到那些參數。比如 email 不是必填:

public Student(string name, int age)
{
    Name = name;
    Age = age;
    Email = "unknown@noemail.com"; // 預設值
}

4. 用 Object Initializer 初始化

建構子可以跟另一種很方便的語法搭配 — 物件初始化器。你可以呼叫建構子,然後在大括號裡直接指定新物件的 property 值


public class Student
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }

    // 建議還是要有建構子
    public Student(string name, int age)
    {
        Name = name;
        Age = age;
        Email = "";
    }
}

Student s = new Student("Антон", 18) { Email = "anton@domain.com" }; // 建構子 + property

這種寫法很適合有些參數有預設值,或 new 的時候不一定知道全部資料的情境。

5. 常見錯誤與小細節

新手用建構子時常常會遇到幾個經典錯誤。來用手指頭數給你看:

錯誤 #1:名字搞混
有時候參數名跟 field 名只差大小寫,很容易搞混。


public Student(string Name, int Age) // 大寫!
{
    Name = Name; // 哎呀!兩個 Name 都指參數,field 沒被初始化。
}

正確寫法:this 指 field:

public Student(string name, int age)
{
    this.Name = name;
    this.Age = age;
}

或是直接用不同名字(像 nameParamageParam),但 this. 這種寫法在大專案裡很推。

錯誤 #2:沒有預設建構子

只要你自己寫了一個建構子,然後又想 new 沒參數的物件 — 會編譯錯誤:

public class Student
{
    public Student(string name) { /*...*/ }
}

// 某處 code
Student s = new Student(); // 錯誤!沒有無參數建構子。

解法: 明確加一個沒參數的建構子:

public Student() { /*...*/ }

錯誤 #3:無限遞迴 — 建構子自己呼叫自己


public Student()
{
    // 錯誤!自己呼叫自己 — 無限遞迴。
    new Student();
}
2
任務
C# SELF, 等級 16, 課堂 3
上鎖
帶參數的建構子
帶參數的建構子
2
任務
C# SELF, 等級 16, 課堂 3
上鎖
初始化包含陣列的複雜物件
初始化包含陣列的複雜物件
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION