如何:使用自动实现的属性实现轻量类(C# 编程指南)How to: Implement a Lightweight Class with Auto-Implemented Properties (C# Programming Guide)

本示例演示如何创建一个仅用于封装一组自动实现的属性的不可变轻型类。This example shows how to create an immutable lightweight class that serves only to encapsulate a set of auto-implemented properties. 当你必须使用引用类型语义时,请使用此种构造而不是结构。Use this kind of construct instead of a struct when you must use reference type semantics.

可通过两种方法来实现不可变的属性:You can make an immutable property in two ways:

  • 可以将 set 访问器声明为专用You can declare the set accessor to be private. 属性只能在该类型中设置,但它对于使用者是不可变的。The property is only settable within the type, but it is immutable to consumers.

    当你声明一个 private set 取值函数时,你无法使用对象初始值设定项来初始化属性。When you declare a private set accessor, you cannot use an object initializer to initialize the property. 你必须使用构造函数或工厂方法。You must use a constructor or a factory method.

  • 也可以仅声明 get 访问器,使属性除了能在该类型的构造函数中可变,在其他任何位置都不可变。You can declare only the get accessor, which makes the property immutable everywhere except in the type’s constructor.

示例Example

下面的示例演示了实现具有自动实现属性的不可变类的两种方法。The following example shows two ways to implement an immutable class that has auto-implemented properties. 这两种方法均使用 private set 声明其中一个属性,使用单独的 get 声明另一个属性。Each way declares one of the properties with a private set and one of the properties with a get only. 第一个类仅使用构造函数来初始化属性,第二个类则使用可调用构造函数的静态工厂方法。The first class uses a constructor only to initialize the properties, and the second class uses a static factory method that calls a constructor.

// This class is immutable. After an object is created,
// it cannot be modified from outside the class. It uses a
// constructor to initialize its properties.
class Contact
{
    // Read-only properties.
    public string Name { get; }
    public string Address { get; private set; }

    // Public constructor.
    public Contact(string contactName, string contactAddress)
    {
        Name = contactName;
        Address = contactAddress;
    }
}

// This class is immutable. After an object is created,
// it cannot be modified from outside the class. It uses a
// static method and private constructor to initialize its properties.
public class Contact2
{
    // Read-only properties.
    public string Name { get; private set; }
    public string Address { get; }

    // Private constructor.
    private Contact2(string contactName, string contactAddress)
    {
        Name = contactName;
        Address = contactAddress;
    }

    // Public factory method.
    public static Contact2 CreateContact(string name, string address)
    {
        return new Contact2(name, address);
    }
}

public class Program
{
    static void Main()
    {
        // Some simple data sources.
        string[] names = {"Terry Adams","Fadi Fakhouri", "Hanying Feng",
                            "Cesar Garcia", "Debra Garcia"};
        string[] addresses = {"123 Main St.", "345 Cypress Ave.", "678 1st Ave",
                                "12 108th St.", "89 E. 42nd St."};

        // Simple query to demonstrate object creation in select clause.
        // Create Contact objects by using a constructor.
        var query1 = from i in Enumerable.Range(0, 5)
                    select new Contact(names[i], addresses[i]);

        // List elements cannot be modified by client code.
        var list = query1.ToList();
        foreach (var contact in list)
        {
            Console.WriteLine("{0}, {1}", contact.Name, contact.Address);
        }

        // Create Contact2 objects by using a static factory method.
        var query2 = from i in Enumerable.Range(0, 5)
                        select Contact2.CreateContact(names[i], addresses[i]);

        // Console output is identical to query1.
        var list2 = query2.ToList();

        // List elements cannot be modified by client code.
        // CS0272:
        // list2[0].Name = "Eugene Zabokritski";

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}

/* Output:
    Terry Adams, 123 Main St.
    Fadi Fakhouri, 345 Cypress Ave.
    Hanying Feng, 678 1st Ave
    Cesar Garcia, 12 108th St.
    Debra Garcia, 89 E. 42nd St.
*/

编译器为每个自动实现的属性创建了支持字段。The compiler creates backing fields for each auto-implemented property. 这些字段无法直接从源代码进行访问。The fields are not accessible directly from source code.

请参阅See also