C#3.0新增功能01 自动实现的属性

在 C# 3.0 及更高版本,当属性访问器中不需要任何其他逻辑时,自动实现的属性会使属性声明更加简洁。 它们还允许客户端代码创建对象。 当你声明以下示例中所示的属性时,编译器将创建仅可以通过该属性的 get 和 set 访问器访问的专用、匿名支持字段。

下列示例演示一个简单的类,它具有某些自动实现的属性:

// 该类是可变的。它的数据可以从类外部修改
class Customer
{
    // 用于普通get和set的自动实现属性
    public double TotalPurchases { get; set; }
    public string Name { get; set; }
    public int CustomerID { get; set; }

    // 构造函数
    public Customer(double purchases, string name, int ID)
    {
        TotalPurchases = purchases;
        Name = name;
        CustomerID = ID;
    }

    // 方法
    public string GetContactInfo() { return "ContactInfo"; }
    public string GetTransactionHistory() { return "History"; }

    // 其他的方法、事件等
}

class Program
{
    static void Main()
    {
        // 初始化一个新对象
        Customer cust1 = new Customer(4987.63, "Northwind", 90108);

        // 修改属性
        cust1.TotalPurchases += 499.99;
    }
}

在 C# 6 和更高版本中,你可以像字段一样初始化自动实现属性:

public string FirstName { get; set; } = "Jane";

上一示例中所示的类是可变的。 创建客户端代码后可以用于更改对象中的值。 在包含重要行为(方法)以及数据的复杂类中,通常有必要具有公共属性。 但是,对于较小类或仅封装一组值(数据)且只有很少行为或没有行为的结构,则应该通过声明 set 访问器为专用(对使用者的不可变)或通过声明仅一个 get 访问器(除构造函数外都不可变),使对象不可变。

使用自动实现的属性实现轻量类

本示例演示如何创建一个仅用于封装一组自动实现的属性的不可变轻型类。 当你必须使用引用类型语义时,请使用此种构造而不是结构。

可通过两种方法来实现不可变的属性:

  • 可以将 set 访问器声明为专用。 属性只能在该类型中设置,但它对于使用者是不可变的。

    当你声明一个 private set 取值函数时,你无法使用对象初始值设定项来初始化属性。你必须使用构造函数或工厂方法。

  • 也可以仅声明 get 访问器,使属性除了能在该类型的构造函数中可变,在其他任何位置都不可变。

下面的示例演示了实现具有自动实现属性的不可变类的两种方法。 这两种方法均使用 private set 声明其中一个属性,使用单独的 get 声明另一个属性。 第一个类仅使用构造函数来初始化属性,第二个类则使用可调用构造函数的静态工厂方法。

 1 // 这个类是不可变的。创建对象后,不能从类外部修改它。它使用构造函数初始化其属性。
 2 class Contact
 3 {
 4     // 公共只读属性
 5     public string Name { get; }
 6     public string Address { get; private set; }
 7 
 8     // 公共构造函数
 9     public Contact(string contactName, string contactAddress)
10     {
11         Name = contactName;
12         Address = contactAddress;
13     }
14 }
15 
16 // 这个类是不可变的。创建对象后,不能从类外部修改它。它使用静态方法和私有构造函数初始化其属性。
17 public class Contact2
18 {
19     // 公共只读属性
20     public string Name { get; private set; }
21     public string Address { get; }
22 
23     // 私有构造函数
24     private Contact2(string contactName, string contactAddress)
25     {
26         Name = contactName;
27         Address = contactAddress;
28     }
29 
30     // 共有工厂方法
31     public static Contact2 CreateContact(string name, string address)
32     {
33         return new Contact2(name, address);
34     }
35 }
36 
37 public class Program
38 {
39     static void Main()
40     {
41         string[] names = {"Terry Adams","Fadi Fakhouri", "Hanying Feng",
42                           "Cesar Garcia", "Debra Garcia"};
43         string[] addresses = {"123 Main St.", "345 Cypress Ave.", "678 1st Ave",
44                               "12 108th St.", "89 E. 42nd St."};
45 
46         // 在 select 子句中演示对象创建的简单查询。使用构造函数创建contact对象。
47         var query1 = from i in Enumerable.Range(0, 5)
48                      select new Contact(names[i], addresses[i]);
49 
50         // 列表元素不能由客户端代码修改。
51         var list = query1.ToList();
52         foreach (var contact in list)
53         {
54             Console.WriteLine("{0}, {1}", contact.Name, contact.Address);
55         }
56 
57         // 使用静态工厂方法创建contact2对象。
58         var query2 = from i in Enumerable.Range(0, 5)
59                      select Contact2.CreateContact(names[i], addresses[i]);
60 
61         // 控制台输出与query1相同。
62         var list2 = query2.ToList();
63 
64         // 列表元素不能由客户端代码修改。
65         // CS0272:
66         // list2[0].Name = "Eugene Zabokritski";
67 
68         // 在调试模式下保持控制台打开。
69         Console.WriteLine("Press any key to exit.");
70         Console.ReadKey();
71     }
72 }
73 
74 /* 输出:
75     Terry Adams, 123 Main St.
76     Fadi Fakhouri, 345 Cypress Ave.
77     Hanying Feng, 678 1st Ave
78     Cesar Garcia, 12 108th St.
79     Debra Garcia, 89 E. 42nd St.
80 */

编译器为每个自动实现的属性创建了支持字段。 这些字段无法直接从源代码进行访问。

 

posted @ 2019-07-11 15:46  张传宁  阅读(857)  评论(0编辑  收藏  举报
页脚 HTML 代码