举例讲解C#中自动实现的属性
在C#3.0及更高版本,当属性访问器中不需要任何其他逻辑时,自动实现的属性会使属性声明更加简洁。它们还允许客户端代码创建对象。当你声明以下示例中所示的属性时,编译器将创建仅可以通过该属性的get和set访问器访问的专用、匿名支持字段。
下列示例演示一个简单的类,它具有某些自动实现的属性:
//Thisclassismutable.Itsdatacanbemodifiedfrom //outsidetheclass. classCustomer { //Auto-ImplPropertiesfortrivialgetandset publicdoubleTotalPurchases{get;set;} publicstringName{get;set;} publicintCustomerID{get;set;} //Constructor publicCustomer(doublepurchases,stringname,intID) { TotalPurchases=purchases; Name=name; CustomerID=ID; } //Methods publicstringGetContactInfo(){return"ContactInfo";} publicstringGetTransactionHistory(){return"History";} //..Additionalmethods,events,etc. } classProgram { staticvoidMain() { //Intializeanewobject. Customercust1=newCustomer(4987.63,"Northwind",90108); //Modifyaproperty cust1.TotalPurchases+=499.99; } }
在C#6和更高版本中,你可以像字段一样初始化自动实现属性:
publicstringFirstName{get;set;}="Jane";
上一示例中所示的类是可变的。创建客户端代码后可以用于更改对象中的值。在包含重要行为(方法)以及数据的复杂类中,通常有必要具有公共属性。但是,对于较小类或仅封装一组值(数据)且只有很少行为或没有行为的结构,则应该通过声明set访问器为专用(对使用者的不可变)或通过声明仅一个get访问器(除构造函数外都不可变),使对象不可变。
动实现的属性上允许使用特性,但很明显支持字段上不允许,因为不能从你的源代码访问它们。如果必须使用属性的支持字段上的特性,只需创建一个常规属性。
使用自动实现的属性实现轻量类
本示例演示如何创建一个仅用于封装一组自动实现的属性的不可变轻型类。当你必须使用引用类型语义时,请使用此种构造而不是结构。
可通过两种方法来实现不可变的属性。可以将set取值函数声明为private。属性只能在该类型中设置,但它对于使用者是不可变的。也可以仅声明get取值函数,使属性除了能在该类型的构造函数中设置,在其他任何位置都不可变。
当你声明一个privateset取值函数时,你无法使用对象初始值设定项来初始化属性。你必须使用构造函数或工厂方法。
示例
下面的示例演示了实现具有自动实现属性的不可变类的两种方法。这两种方法均使用privateset声明其中一个属性,使用单独的get声明另一个属性。第一个类仅使用构造函数来初始化属性,第二个类则使用可调用构造函数的静态工厂方法。
//Thisclassisimmutable.Afteranobjectiscreated, //itcannotbemodifiedfromoutsidetheclass.Itusesa //constructortoinitializeitsproperties. classContact { //Read-onlyproperties. publicstringName{get;} publicstringAddress{get;privateset;} //Publicconstructor. publicContact(stringcontactName,stringcontactAddress) { Name=contactName; Address=contactAddress; } } //Thisclassisimmutable.Afteranobjectiscreated, //itcannotbemodifiedfromoutsidetheclass.Itusesa //staticmethodandprivateconstructortoinitializeitsproperties. publicclassContact2 { //Read-onlyproperties. publicstringName{get;privateset;} publicstringAddress{get;} //Privateconstructor. privateContact2(stringcontactName,stringcontactAddress) { Name=contactName; Address=contactAddress; } //Publicfactorymethod. publicstaticContact2CreateContact(stringname,stringaddress) { returnnewContact2(name,address); } } publicclassProgram { staticvoidMain() { //Somesimpledatasources. string[]names={"TerryAdams","FadiFakhouri","HanyingFeng", "CesarGarcia","DebraGarcia"}; string[]addresses={"123MainSt.","345CypressAve.","6781stAve", "12108thSt.","89E.42ndSt."}; //Simplequerytodemonstrateobjectcreationinselectclause. //CreateContactobjectsbyusingaconstructor. varquery1=fromiinEnumerable.Range(0,5) selectnewContact(names[i],addresses[i]); //Listelementscannotbemodifiedbyclientcode. varlist=query1.ToList(); foreach(varcontactinlist) { Console.WriteLine("{0},{1}",contact.Name,contact.Address); } //CreateContact2objectsbyusingastaticfactorymethod. varquery2=fromiinEnumerable.Range(0,5) selectContact2.CreateContact(names[i],addresses[i]); //Consoleoutputisidenticaltoquery1. varlist2=query2.ToList(); //Listelementscannotbemodifiedbyclientcode. //CS0272: //list2[0].Name="EugeneZabokritski"; //Keeptheconsoleopenindebugmode. Console.WriteLine("Pressanykeytoexit."); Console.ReadKey(); } }
输出:
TerryAdams,123MainSt. FadiFakhouri,345CypressAve. HanyingFeng,6781stAve CesarGarcia,12108thSt. DebraGarcia,89E.42ndSt.
编译器为每个自动实现的属性创建了支持字段。这些字段无法直接从源代码进行访问。