属性(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.

  • value 关键字用于定义由 set 访问器分配的值。The value keyword is used to define the value being assigned by the set accessor.

  • 属性可以是读-写属性(既有 get 访问器又有 set 访问器)、只读属性(有 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. 可以将这些属性作为 expression-bodied 成员来实现。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 访问器作为 expression-bodied 成员实现。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 属性作为 expression-bodied 成员实现。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 访问器都可以作为 expression-bodied 成员实现。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