屬性 (C# 程式設計手冊)
屬性是提供彈性機制以讀取、寫入或計算私用欄位值的成員。 屬性可以像公用資料成員一樣使用,但它們是稱為 存取子的特殊方法。 這項功能可讓您輕鬆存取資料,但仍有助於提升方法的安全性和彈性。
屬性概觀
- 屬性可讓類別公開取得和設定值的公用方式,同時隱藏實作或驗證程式碼。
- get 屬性存取子可用來傳回屬性值,而 set 屬性存取子則用來指派新值。 在 C# 9 和更新版本中, init 屬性存取子只會用來在物件建構期間指派新的值。 這些存取子可以有不同的存取層級。 如需詳細資訊,請參閱限制存取子的存取範圍。
- value關鍵字可用來定義 或
init
存取子所set
指派的值。 - 屬性可以是「讀寫」(同時具有
get
和set
存取子)、「唯讀」(具有get
存取子但沒有set
存取子) 或「唯寫」(具有set
存取子但沒有get
存取子)。 唯寫屬性很少見,而且最常用來限制對機密資料的存取。 - 不需要自訂存取子程式碼的簡單屬性,則可以實作為運算式主體定義或自動實作屬性。
含有支援欄位的屬性
實作屬性的一種基本模式需要使用私用支援欄位,來設定和擷取屬性值。 get
存取子會傳回私用欄位的值,而 set
存取子則可能會執行一些資料驗證,再將值指派給私用欄位。 這兩個存取子在儲存或傳回資料之前,也可以對資料執行一些轉換或計算。
下列範例將示範這個模式。 在此範例中,TimePeriod
類別代表時間間隔。 就內部而言,此類別會將時間間隔 (秒) 儲存在名為 _seconds
的私用欄位中。 名為 Hours
的讀寫屬性可讓客戶以小時為單位指定時間間隔。 get
和 set
存取子都會執行小時與秒之間的必要轉換。 此外,set
存取子會驗證資料,並在小時數無效時擲回 ArgumentOutOfRangeException。
public class TimePeriod
{
private double _seconds;
public double Hours
{
get { return _seconds / 3600; }
set
{
if (value < 0 || value > 24)
throw new ArgumentOutOfRangeException(nameof(value),
"The valid range is between 0 and 24.");
_seconds = value * 3600;
}
}
}
您可以存取屬性以取得和設定值,如下列範例所示:
TimePeriod t = new TimePeriod();
// The property assignment causes the 'set' accessor to be called.
t.Hours = 24;
// Retrieving the property causes the 'get' accessor to be called.
Console.WriteLine($"Time in hours: {t.Hours}");
// The example displays the following output:
// Time in hours: 24
運算式主體定義
屬性存取子通常是由只會指派或傳回運算式結果的單行陳述式所組成。 您可以將這些屬性實作為運算式主體成員。 運算式主體定義包含 =>
符號,後面接著要從屬性指派或擷取的運算式。
唯讀屬性可以將存取子實 get
作為運算式主體成員。 在此情況下,不會使用 get
存取子關鍵字和 return
關鍵字。 下列範例會將唯讀 Name
屬性實作為運算式主體成員。
public class Person
{
private string _firstName;
private string _lastName;
public Person(string first, string last)
{
_firstName = first;
_lastName = last;
}
public string Name => $"{_firstName} {_lastName}";
}
get
和 存取 set
子都可以實作為運算式主體成員。 在此情況下,必須同時有 get
和 set
關鍵字。 下列範例說明如何使用運算式主體定義來表示這兩個存取子。 關鍵字 return
不會與 存取子搭配 get
使用。
public class SaleItem
{
string _name;
decimal _cost;
public SaleItem(string name, decimal cost)
{
_name = name;
_cost = cost;
}
public string Name
{
get => _name;
set => _name = value;
}
public decimal Price
{
get => _cost;
set => _cost = value;
}
}
自動實作屬性
在某些情況下,屬性 get
和 set
存取子只會指派值,或從備份欄位擷取值,而不需要包含任何額外的邏輯。 藉由使用自動實作屬性,您可以簡化程式碼,同時讓 C# 編譯器無障礙地為您提供支援欄位。
如果屬性同時具有 get
和 set
(或 get
和 和 init
) 存取子,則必須自動實作兩者。 您可以使用 get
和 set
關鍵字,但不提供任何實作,來定義自動實作屬性。 下列範例會重複上一個範例,不同之處在於 Name
和 Price
為自動實作屬性。 此範例也會移除參數化建構函式,讓 SaleItem
物件現在會透過呼叫無參數建構函式和 物件初始化運算式來初始化。
public class SaleItem
{
public string Name
{ get; set; }
public decimal Price
{ get; set; }
}
自動實作的屬性可以宣告 和 set
存取子的不同協助工具 get
。 您通常會宣告公用 get
存取子和私 set
用存取子。 您可以在 限制存取子存取範圍一文中深入瞭解。
必要屬性
從 C# 11 開始,您可以新增 required
成員以強制用戶端程式代碼初始化任何屬性或欄位:
public class SaleItem
{
public required string Name
{ get; set; }
public required decimal Price
{ get; set; }
}
若要建立 SaleItem
,您必須使用物件初始化運算式來設定 Name
和 Price
屬性,如下列程式碼所示:
var item = new SaleItem { Name = "Shoes", Price = 19.95m };
Console.WriteLine($"{item.Name}: sells for {item.Price:C2}");
相關章節
C# 語言規格
如需詳細資訊,請參閱 C# 語言規格的屬性。 語言規格是 C# 語法及用法的限定來源。