CodeGym /課程 /C# SELF /C# 裡的屬性 (Properties)

C# 裡的屬性 (Properties)

C# SELF
等級 17, 課堂 1
開放

1. 前言

我們先來聊聊直接用欄位會遇到什麼問題。如果你把欄位宣告成 public,那它就可以被程式裡任何地方直接改掉:

public class Dog
{
    public string Name;
}

Dog dog = new Dog();
dog.Name = ""; // O_o ... 這就像「狗的名字 = 空字串」!

使用者可以把 Name 欄位設成完全沒意義的值,像是空字串、太長的名字,甚至 null。這就像你讓人組裝你的 IKEA 新衣櫃,結果你直接給他木工廠的所有權限。

提醒一下,封裝 就是物件自己掌控自己的資料。我們不會讓每個路人都能碰內部資料,而是給一個專門的「門」——屬性(Properties),大家只能透過這個門進出,這樣你就能加檢查、記錄、修改或其他反應。

2. 定義和語法

屬性 是 class 的一種特殊成員,看起來很像欄位,但其實底層是兩個特殊方法:getter(拿值)和 setter(設值)。用屬性你可以:

  • 允許(或禁止)讀/寫資料;
  • 存取時加驗證或邏輯;
  • 把內部欄位藏起來,甚至把值存到別的地方。

屬性的宣告很像欄位,只是多了大括號,裡面有 get 跟 set 關鍵字。


[存取修飾詞] 型別 屬性名稱
{
    get { ... }
    set { ... }
}
屬性宣告範本

來看我們 Dog class 的例子:

public class Dog
{
    private string _name; // 內部欄位(private!)

    public string Name
    {
        get { return _name; }  // "getter":拿名字
        set { _name = value; } // "setter":設名字
    }
}

小提醒: 底線通常用在 private 欄位(_name)。這是 C# 的寫法慣例。

3. 屬性的運作機制

屬性就像「守門員」,站在物件內部資料和外部世界之間。舉例:

Dog dog = new Dog();
dog.Name = "Шарик";
Console.WriteLine(dog.Name);

說明:

  • 當程式跑到 dog.Name = "Шарик"; 這行時,其實是呼叫屬性的 set 方法,你可以在這裡加任何檢查(像是名字不能是空的)。
  • 當 Console.WriteLine(dog.Name); 執行時,就是呼叫 get 方法,直接回傳目前的值,或是你想要動態算出來的東西。

看起來像一般欄位,其實一切都在你掌控中!

4. 為什麼屬性是 "Best Practice"

大多數時候我們不會讓外部直接碰物件的內部欄位。就算現在覺得不用檢查,養成用屬性包資料的習慣,等規則變了你會很感謝自己。

「設值時驗證」範例:


public class Dog
{
    private string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                throw new ArgumentException("狗的名字不能是空的!");
            }
            _name = value;
        }
    }
}

現在這樣:

dog.Name = ""; // 會丟出例外!

… 保護你的物件不會被設成奇怪的值。

5. 屬性:唯讀、唯寫、一般

有時你只想讓人看值(像狗的出生年,不能改),或只讓人設值(很少見,但你想搞神祕也可以)。

  • 唯讀: 只寫 get,不寫 set。
  • 唯寫: 只寫 set,不寫 get。

範例:

public class Dog
{
    private int _birthYear = 2018;

    // 唯讀
    public int BirthYear
    {
        get { return _birthYear; }
    }

    // 唯寫(超少見)
    public string Secret
    {
        set { /* 處理 value */ }
    }
}

6. 屬性 vs 欄位

欄位 屬性
語法
public string Name;
public string Name { get; set; }
存取 直接 透過 get/set
驗證 沒有 可以加在 set/get
擴充性 沒有 隨時可以改
IDE 整合 看起來像欄位 看起來像屬性(對 framework 很重要)

圖解:屬性的運作

sequenceDiagram
participant User as 物件的使用者
participant Dog as Dog 物件
participant Field as 私有欄位 _name

User->>Dog: dog.Name = "Рыжик"
Dog->>Dog: set Name("Рыжик")
Dog->>Field: _name = "Рыжик"

User->>Dog: print(dog.Name)
Dog->>Dog: get Name()
Dog->>Field: 讀取 _name
Dog->>User: 回傳 "Рыжик"

7. 常見錯誤和小細節

來看看會踩到哪些坑。

常見錯誤——搞混欄位和屬性,不小心把 private 資料暴露出去:

public string name; // 這是欄位!到處都看得到,危險!

正確寫法:

private string _name;
public string Name
{
    get { return _name; }
    set { _name = value; }
}

靜態屬性 也有,就是給所有物件共用的值。但要小心用。

有趣: 如果屬性只有 get,又沒 constructor,那它根本不能改——這叫 immutable property,在現代設計很常見(我們之後講 record 和資料不可變時會細講)。

2
任務
C# SELF, 等級 17, 課堂 1
上鎖
宣告具有 get 和 set 存取子的屬性
宣告具有 get 和 set 存取子的屬性
2
任務
C# SELF, 等級 17, 課堂 1
上鎖
帶有輸入驗證的屬性
帶有輸入驗證的屬性
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION