屬性 (C# 程式設計手冊)Properties (C# Programming Guide)

屬性是提供彈性機制以讀取、寫入或計算私用欄位值的成員。A property is a member that provides a flexible mechanism to read, write, or compute the value of a private field. 使用屬性時可將其視為公用資料成員,但實際上屬性是名為「存取子」 的特殊方法。Properties can be used as if they are public data members, but they are actually special methods called accessors. 如此可讓資料更容易存取,同時有助於提升方法的安全性和彈性。This enables data to be accessed easily and still helps promote the safety and flexibility of methods.

屬性概觀Properties overview

  • 屬性可讓類別公開取得和設定值的公用方式,同時隱藏實作或驗證程式碼。Properties enable a class to expose a public way of getting and setting values, while hiding implementation or verification code.

  • get 屬性存取子可用來傳回屬性值,而 set 屬性存取子則用來指派新值。A get property accessor is used to return the property value, and a set property accessor is used to assign a new value. 這些存取子可以有不同的存取層級。These accessors can have different access levels. 如需詳細資訊,請參閱限制存取子的存取範圍For more information, see Restricting Accessor Accessibility.

  • valueset 關鍵字是用來定義 存取子要指派的值。The value keyword is used to define the value being assigned by the set accessor.

  • 屬性可以是「讀寫」 (同時具有 getset 存取子)、「唯讀」 (具有 get 存取子但沒有 set 存取子) 或「唯寫」 (具有 set 存取子但沒有 get 存取子)。Properties can be read-write (they have both a get and a set accessor), read-only (they have a get accessor but no set accessor), or write-only (they have a set accessor, but no get accessor). 唯寫屬性很少見,而且最常用來限制對機密資料的存取。Write-only properties are rare and are most commonly used to restrict access to sensitive data.

  • 不需要自訂存取子程式碼的簡單屬性,則可以實作為運算式主體定義或自動實作屬性Simple properties that require no custom accessor code can be implemented either as expression body definitions or as auto-implemented properties.

含有支援欄位的屬性Properties with backing fields

實作屬性的一種基本模式需要使用私用支援欄位,來設定和擷取屬性值。One basic pattern for implementing a property involves using a private backing field for setting and retrieving the property value. get 存取子會傳回私用欄位的值,而 set 存取子則可能會執行一些資料驗證,再將值指派給私用欄位。The get accessor returns the value of the private field, and the set accessor may perform some data validation before assigning a value to the private field. 這兩個存取子也可能會對資料執行一些轉換或計算,再儲存或傳回資料。Both accessors may also perform some conversion or computation on the data before it is stored or returned.

下列範例將示範這個模式。The following example illustrates this pattern. 在此範例中,TimePeriod 類別代表時間間隔。In this example, the TimePeriod class represents an interval of time. 就內部而言,此類別會將時間間隔 (秒) 儲存在名為 _seconds 的私用欄位中。Internally, the class stores the time interval in seconds in a private field named _seconds. 名為 Hours 的讀寫屬性可讓客戶以小時為單位指定時間間隔。A read-write property named Hours allows the customer to specify the time interval in hours. getset 存取子都會執行小時與秒之間的必要轉換。Both the get and the set accessors perform the necessary conversion between hours and seconds. 此外,set 存取子會驗證資料,並在小時數無效時擲回 ArgumentOutOfRangeExceptionIn addition, the set accessor validates the data and throws an ArgumentOutOfRangeException if the number of hours is invalid.

using System;

class TimePeriod
{
   private double _seconds;

   public double Hours
   {
       get { return _seconds / 3600; }
       set { 
          if (value < 0 || value > 24)
             throw new ArgumentOutOfRangeException(
                   $"{nameof(value)} must be between 0 and 24.");

          _seconds = value * 3600; 
       }
   }
}

class Program
{
   static void Main()
   {
       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

運算式主體定義Expression body definitions

屬性存取子通常是由只會指派或傳回運算式結果的單行陳述式所組成。Property accessors often consist of single-line statements that just assign or return the result of an expression. 您可以將這些屬性實作為運算式主體成員。You can implement these properties as expression-bodied members. 運算式主體定義包含 => 符號,後面接著要從屬性指派或擷取的運算式。Expression body definitions consist of the => symbol followed by the expression to assign to or retrieve from the property.

從 C# 6 開始,唯讀屬性可將 get 存取子實作為運算式主體成員。Starting with C# 6, read-only properties can implement the get accessor as an expression-bodied member. 在此情況下,不會使用 get 存取子關鍵字和 return 關鍵字。In this case, neither the get accessor keyword nor the return keyword is used. 下列範例會將唯讀 Name 屬性實作為運算式主體成員。The following example implements the read-only Name property as an expression-bodied member.

using System;

public class Person
{
   private string _firstName;
   private string _lastName;
   
   public Person(string first, string last)
   {
      _firstName = first;
      _lastName = last;
   }

   public string Name => $"{_firstName} {_lastName}";   
}

public class Example
{
   public static void Main()
   {
      var person = new Person("Isabelle", "Butts");
      Console.WriteLine(person.Name);
   }
}
// The example displays the following output:
//      Isabelle Butts

從 C# 7.0 開始,可同時將 getset 存取子實作為運算式主體成員。Starting with C# 7.0, both the get and the set accessor can be implemented as expression-bodied members. 在此情況下,必須同時有 getset 關鍵字。In this case, the get and set keywords must be present. 下列範例說明如何使用運算式主體定義來表示這兩個存取子。The following example illustrates the use of expression body definitions for both accessors. 請注意,return 關鍵字不能搭配 get 存取子使用。Note that the return keyword is not used with the get accessor.

using System;

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; 
   }
}

class Program
{
   static void Main(string[] args)
   {
      var item = new SaleItem("Shoes", 19.95m);
      Console.WriteLine($"{item.Name}: sells for {item.Price:C2}");
   }
}
// The example displays output like the following:
//       Shoes: sells for $19.95



自動實作屬性Auto-implemented properties

在某些情況下,屬性 getset 存取子只會指派值給支援欄位,或從支援欄位中擷取值,而不會包含任何其他邏輯。In some cases, property get and set accessors just assign a value to or retrieve a value from a backing field without including any additional logic. 藉由使用自動實作屬性,您可以簡化程式碼,同時讓 C# 編譯器無障礙地為您提供支援欄位。By using auto-implemented properties, you can simplify your code while having the C# compiler transparently provide the backing field for you.

如果屬性具有 getset 存取子,這兩者都必須自動實作。If a property has both a get and a set accessor, both must be auto-implemented. 您可以使用 getset 關鍵字,但不提供任何實作,來定義自動實作屬性。You define an auto-implemented property by using the get and set keywords without providing any implementation. 下列範例會重複上一個範例,不同之處在於 NamePrice 為自動實作屬性。The following example repeats the previous one, except that Name and Price are auto-implemented properties. 請注意,此範例也會移除參數化建構函式,因此 SaleItem 物件現在會透過呼叫無參數建構函式和物件初始設定式來初始化。Note that the example also removes the parameterized constructor, so that SaleItem objects are now initialized with a call to the parameterless constructor and an object initializer.

using System;

public class SaleItem
{
   public string Name 
   { get; set; }

   public decimal Price
   { get; set; }
}

class Program
{
   static void Main(string[] args)
   {
      var item = new SaleItem{ Name = "Shoes", Price = 19.95m };
      Console.WriteLine($"{item.Name}: sells for {item.Price:C2}");
   }
}
// The example displays output like the following:
//       Shoes: sells for $19.95



C# 語言規格C# Language Specification

如需詳細資訊,請參閱 C# 語言規格屬性For more information, see Properties in the C# Language Specification. 語言規格是 C# 語法及用法的限定來源。The language specification is the definitive source for C# syntax and usage.

另請參閱See also