ฉันสร้างคุณสมบัติอัตโนมัติ:
public int Foo { get; }
นี่คือ getter เท่านั้น แต่เมื่อฉันสร้างตัวสร้างฉันสามารถเปลี่ยนค่า:
public MyClass(string name)
{
Foo = 5;
}
ทำไมถึงเป็นไปได้ทั้งๆที่เป็นแบบ get-only?
ฉันสร้างคุณสมบัติอัตโนมัติ:
public int Foo { get; }
นี่คือ getter เท่านั้น แต่เมื่อฉันสร้างตัวสร้างฉันสามารถเปลี่ยนค่า:
public MyClass(string name)
{
Foo = 5;
}
ทำไมถึงเป็นไปได้ทั้งๆที่เป็นแบบ get-only?
คำตอบ:
นี่คือคุณลักษณะ C # 6 ใหม่ "คุณสมบัติอัตโนมัติสำหรับ Getter เท่านั้น" หรือที่เรียกว่า "Auto-Property Initializers for Read-Only Properties" ตามที่กล่าวไว้ในบทความในนิตยสาร MSDN 'C #: The New and Improved C # 6.0' โดย Mark MichaelisและในC # 6.0 ร่างภาษาข้อมูลจำเพาะ
ตัวตั้งค่าของฟิลด์แบบอ่านอย่างเดียวสามารถเข้าถึงได้ในตัวสร้างเท่านั้นในสถานการณ์อื่น ๆ ทั้งหมดฟิลด์ยังคงอ่านอย่างเดียวและทำงานเหมือนเดิม
นี่คือไวยากรณ์ที่สะดวกในการลดจำนวนรหัสที่คุณต้องพิมพ์และเพื่อลบความจำเป็นในการประกาศตัวแปรระดับโมดูลส่วนตัวอย่างชัดเจนเพื่อเก็บค่า
คุณลักษณะนี้ถูกมองว่ามีความสำคัญเนื่องจากมีการนำคุณสมบัติที่ใช้งานอัตโนมัติมาใช้ใน C # 3 คุณสมบัติที่ไม่แน่นอน (ผู้ที่มีตัวรับและตัวตั้งค่า) ได้กลายเป็นสิ่งที่เขียนได้เร็วกว่าคุณสมบัติที่ไม่เปลี่ยนรูป ถูกล่อลวงให้ใช้คุณสมบัติที่เปลี่ยนแปลงได้เพื่อหลีกเลี่ยงการพิมพ์รหัสสำหรับเขตข้อมูลสำรองที่มักจะต้องใช้สำหรับคุณสมบัติอ่านอย่างเดียว มีการอภิปรายมากขึ้นของคุณสมบัติ Auto-ดำเนินการในเป็นส่วนที่เกี่ยวข้องของไมโครซอฟท์เขียนโปรแกรม C # คู่มือ
บล็อกโพสต์นี้ '# 1,207 - C # 6.0 - ตัวเริ่มต้นคุณสมบัติอัตโนมัติสำหรับคุณสมบัติอ่านอย่างเดียว' โดย Sean Sextonมีคำอธิบายและตัวอย่างที่ดีดังต่อไปนี้:
ก่อนหน้า C # 6.0 หากคุณต้องการคุณสมบัติแบบอ่านอย่างเดียว (ไม่เปลี่ยนรูป) โดยทั่วไปคุณจะใช้ฟิลด์การสำรองข้อมูลแบบอ่านอย่างเดียวที่เริ่มต้นในตัวสร้างดังที่แสดงด้านล่าง
public class Dog { public string Name { get; set; } // DogCreationTime is immutable private readonly DateTime creTime; public DateTime DogCreationTime { get { return creTime; } } public Dog(string name) { Name = name; creTime = DateTime.Now; } }
ใน C # 6.0 คุณสามารถใช้คุณสมบัติที่ติดตั้งอัตโนมัติเพื่อใช้คุณสมบัติแบบอ่านอย่างเดียว คุณทำได้โดยใช้ตัวเริ่มต้นคุณสมบัติอัตโนมัติ ผลลัพธ์ที่ได้จะสะอาดกว่าตัวอย่างข้างต้นมากซึ่งเราต้องประกาศเขตข้อมูลสำรองอย่างชัดเจน
public class Dog { public string Name { get; set; } // DogCreationTime is immutable public DateTime DogCreationTime { get; } = DateTime.Now; public Dog(string name) { Name = name; } }
รายละเอียดเพิ่มเติมสามารถพบได้ในrepo dotnet Roslyn บน GitHub :
คุณสมบัติอัตโนมัติสามารถประกาศได้โดยไม่ต้องใช้ตัวตั้งค่า
ฟิลด์สำรองของคุณสมบัติอัตโนมัติ getter-only ถูกประกาศโดยปริยายว่าเป็นแบบอ่านอย่างเดียว (แม้ว่าจะมีความสำคัญเพื่อจุดประสงค์ในการสะท้อนเท่านั้น) สามารถเริ่มต้นได้โดยใช้ initializer บนคุณสมบัติดังตัวอย่างด้านบน นอกจากนี้คุณสมบัติ getter-only สามารถถูกกำหนดให้ในเนื้อหาตัวสร้างของชนิดการประกาศซึ่งทำให้ค่าถูกกำหนดโดยตรงไปยังฟิลด์ที่อยู่ภายใต้:
นี่เป็นเรื่องเกี่ยวกับการแสดงประเภทอย่างรัดกุมมากขึ้น แต่โปรดทราบว่ามันยังลบความแตกต่างที่สำคัญในภาษาระหว่างประเภทที่ไม่แน่นอนและไม่เปลี่ยนรูป: คุณสมบัติอัตโนมัติเป็นชวเลขที่ใช้ได้ก็ต่อเมื่อคุณเต็มใจที่จะทำให้ชั้นเรียนของคุณไม่แน่นอนและสิ่งล่อใจที่จะเริ่มต้น มันเยี่ยมมาก ตอนนี้ด้วยคุณสมบัติอัตโนมัติที่ได้รับเท่านั้นสนามเด็กเล่นได้รับการปรับระดับระหว่างไม่แน่นอนและไม่เปลี่ยนรูป
และในข้อกำหนดภาษาแบบร่าง C # 6.0 (หมายเหตุ: ข้อกำหนดของภาษาถือเป็นที่สิ้นสุดเท่าที่ Microsoft เกี่ยวข้อง แต่ยังไม่ได้รับการอนุมัติให้เป็นมาตรฐาน EMCA / ISOดังนั้นจึงเป็น 'ร่าง'):
ใช้คุณสมบัติโดยอัตโนมัติ
คุณสมบัติที่นำไปใช้โดยอัตโนมัติ (หรือคุณสมบัติอัตโนมัติสำหรับระยะสั้น) เป็นคุณสมบัติที่ไม่ใช่นามธรรมที่ไม่ใช่ภายนอกที่มีเนื้อหาของตัวเข้าถึงอัฒภาคเท่านั้น คุณสมบัติอัตโนมัติต้องมี get accessor และสามารถเลือก set accessor ได้
เมื่อคุณสมบัติถูกระบุเป็นคุณสมบัติที่ใช้งานโดยอัตโนมัติฟิลด์สำรองที่ซ่อนไว้จะพร้อมใช้งานโดยอัตโนมัติสำหรับคุณสมบัติและตัวเข้าถึงจะถูกนำไปใช้เพื่ออ่านและเขียนไปยังฟิลด์สำรองนั้น หากคุณสมบัติอัตโนมัติไม่มีการตั้งค่าตัวเข้าถึงฟิลด์สำรองจะถือว่าเป็นแบบอ่านอย่างเดียว (ฟิลด์แบบอ่านอย่างเดียว) เช่นเดียวกับฟิลด์แบบอ่านอย่างเดียวคุณสมบัติอัตโนมัติแบบ getter-only ยังสามารถกำหนดให้ในเนื้อความของตัวสร้างของคลาสที่ปิดล้อม การมอบหมายดังกล่าวจะกำหนดโดยตรงไปยังฟิลด์สำรองข้อมูลแบบอ่านอย่างเดียวของคุณสมบัติ
คุณสมบัติอัตโนมัติอาจมีตัวเลือก property_initializer ซึ่งถูกนำไปใช้โดยตรงกับฟิลด์การสำรองข้อมูลเป็น variable_initializer (Variable initializers)
CS0200 C# Property or indexer cannot be assigned to -- it is read only
เมื่อใช้คุณสมบัติปกติ "คุณสมบัติอัตโนมัติสำหรับ Getter เท่านั้น" ถือเป็นแบบอ่านอย่างเดียวหรือไม่
นี่เป็นคุณสมบัติใหม่ใน C # 6ที่ให้คุณสร้างคุณสมบัติแบบอ่านอย่างเดียวและเริ่มต้นค่าจากตัวสร้าง (หรืออินไลน์เมื่อคุณประกาศ)
หากคุณพยายามเปลี่ยนค่าของคุณสมบัตินี้นอกตัวสร้างมันจะทำให้คุณมีข้อผิดพลาดในการคอมไพล์
เป็นแบบอ่านอย่างเดียวในแง่ที่เมื่อคุณเริ่มต้นค่า (แบบอินไลน์หรือภายในตัวสร้าง) คุณจะไม่สามารถเปลี่ยนค่าได้
หากไม่สามารถเตรียมใช้งานคุณสมบัติอ่านอย่างเดียวจากตัวสร้าง (หรือตัวเริ่มต้นคุณสมบัติอัตโนมัติ) ก็จะไม่มีประโยชน์เนื่องจากจะส่งคืนค่าเริ่มต้นสำหรับประเภทของมันเสมอ (0 สำหรับตัวเลขค่าว่างสำหรับชนิดการอ้างอิง ). ความหมายเดียวกันนี้ใช้กับฟิลด์แบบอ่านอย่างเดียวในเวอร์ชัน C # ทั้งหมด
ในการกำหนดคุณสมบัติ getter-only ที่แท้จริง (ซึ่งไม่สามารถเตรียมใช้งานได้จากตัวสร้าง) คุณต้องระบุสิ่งที่ส่งคืนเป็นส่วนหนึ่งของนิยาม:
public int Foo { get { return 5; } }
หรือกระชับมากขึ้นใน C # 6:
public int Foo => 5;
"คุณสมบัติที่ใช้งานโดยอัตโนมัติแบบอ่านอย่างเดียว"
ก่อนอื่นอยากชี้แจงว่าคุณสมบัติเช่น
public string FirstName { get; }
เรียกว่า "คุณสมบัติที่ใช้งานโดยอัตโนมัติแบบอ่านอย่างเดียว"
ในการตรวจสอบสิ่งนี้คุณสามารถเรียกใช้และตรวจสอบโค้ดด้านบนด้วย Visual Studio หากคุณเปลี่ยนเวอร์ชันภาษาจาก C # 6.0 เป็น C # 5.0 คอมไพเลอร์จะโยนข้อยกเว้นต่อไปนี้ คุณสมบัติ 'คุณสมบัติที่ใช้งานโดยอัตโนมัติแบบอ่านอย่างเดียว' ไม่พร้อมใช้งานใน C # 5 โปรดใช้ภาษาเวอร์ชัน 6 ขึ้นไป
หากต้องการเปลี่ยนเวอร์ชันภาษา C # โปรดไปที่นี่
ตอนนี้ฉันมาถึงคำถามที่สองของคุณ
“ นี่เป็นเพียงผู้เริ่มต้นเท่านั้น แต่เมื่อฉันสร้างตัวสร้างฉันสามารถเปลี่ยนค่าได้”
Microsoft แนะนำ "คุณสมบัติที่ใช้งานโดยอัตโนมัติแบบอ่านอย่างเดียว" บนตรรกะของการอ่านอย่างเดียว อย่างที่เราทราบกันดีว่าคำหลัก“ อ่านอย่างเดียว” มีให้ตั้งแต่ C # 1.0 เราใช้“อ่านได้อย่างเดียว” เป็นคำหลักปรับปรุงบนสนามและข้อมูลที่สามารถกำหนดใน2 วิธีอย่างใดอย่างหนึ่งในช่วงเวลาของการประกาศหรือในผู้สร้างในระดับเดียวกัน
ในทำนองเดียวกันค่าของ "คุณสมบัติที่ใช้งานโดยอัตโนมัติแบบอ่านอย่างเดียว" สามารถกำหนดได้ 2 วิธี
Way1 (ในขณะที่ประกาศ):
public string FirstName { get; } = "Banketeshvar";
Way2 (ในตัวสร้างในคลาสเดียวกัน)
Person()
{
FirstName = "Banketeshvar";
}
คุณสมบัติอ่านอย่างเดียวล้วนๆ
หากคุณกำลังมองหาสถานที่ให้บริการอ่านอย่างเดียวอย่างหมดจดให้ไปที่สิ่งนี้
public string FullName => "Manish Sharma";
ตอนนี้คุณไม่สามารถกำหนดค่าที่เหมาะสมของ“ FullName” จากตัวสร้างได้ หากคุณพยายามทำเช่นนั้นจะทำให้เกิดข้อยกเว้นต่อไปนี้
"คุณสมบัติหรือผู้จัดทำดัชนี" Person.FullName "ไม่สามารถกำหนดให้ - เป็นแบบอ่านอย่างเดียว"
คุณลักษณะคุณสมบัติอัตโนมัติถูกเพิ่มลงในภาษาในระหว่างการเผยแพร่ C # 3.0 ช่วยให้คุณกำหนดคุณสมบัติได้โดยไม่ต้องมีฟิลด์สำรอง แต่คุณยังต้องใช้ตัวสร้างเพื่อเริ่มต้นคุณสมบัติอัตโนมัติเหล่านี้เป็นค่าที่ไม่ใช่ค่าเริ่มต้น C # 6.0 แนะนำคุณสมบัติใหม่ที่เรียกว่า auto property initializer ซึ่งช่วยให้คุณสามารถเริ่มต้นคุณสมบัติเหล่านี้ได้โดยไม่ต้องมีตัวสร้างเช่นด้านล่าง:
ก่อนหน้านี้ต้องใช้ตัวสร้างหากคุณต้องการสร้างวัตถุโดยใช้คุณสมบัติอัตโนมัติและเริ่มต้นคุณสมบัติอัตโนมัติเป็นค่าที่ไม่ใช่ค่าเริ่มต้นดังต่อไปนี้:
public class MyClass
{
public int Foo { get; }
public Foo(int foo)
{
Foo = foo;
}
}
ตอนนี้ใน C # 6.0 ความสามารถในการใช้ initializer กับคุณสมบัติอัตโนมัติหมายความว่าไม่จำเป็นต้องมีรหัสตัวสร้างที่ชัดเจน
public string Foo { get; } = "SomeString";
public List<string> Genres { get; } = new List<string> { "Comedy", "Drama" };
ตัวแปรที่ประกาศreadonly
สามารถเขียนได้ภายในคอนสตรัคเตอร์ แต่ในภาษาที่ใช้กับแอ็ตทริบิวต์จะไม่สามารถแก้ไขได้หลังจากคอนสตรัคเตอร์ส่งคืน ตัวกำหนดคุณสมบัตินั้นถูกจัดให้เป็นคุณลักษณะของภาษาเนื่องจากมักจำเป็นสำหรับฟิลด์ที่ค่าจะแตกต่างกันไปตามพารามิเตอร์ตัวสร้าง (หมายความว่าไม่สามารถเริ่มต้นได้ก่อนที่ตัวสร้างจะเริ่มทำงาน) แต่จะไม่ต้องเปลี่ยนหลังจากตัวสร้างกลับมา แต่มันก็เป็น ใช้ได้เฉพาะกับตัวแปรที่แสดงเป็นฟิลด์ ความหมายของreadonly
เขตข้อมูลที่มีคุณสมบัติเหมาะสมในหลาย ๆ กรณีจะสมบูรณ์แบบสำหรับสมาชิกสาธารณะยกเว้นว่าชั้นเรียนมักจะเปิดเผยสมาชิก - แม้กระทั่งสิ่งที่ไม่เปลี่ยนรูป - เป็นคุณสมบัติมากกว่าเขตข้อมูล
เช่นเดียวกับคุณสมบัติอัตโนมัติแบบอ่าน - เขียนที่มีอยู่เพื่อให้คลาสแสดงคุณสมบัติที่เปลี่ยนแปลงได้อย่างง่ายดายเช่นเดียวกับฟิลด์ทั่วไปคุณสมบัติอัตโนมัติแบบอ่านอย่างเดียวก็มีอยู่เพื่อให้คลาสแสดงคุณสมบัติที่ไม่เปลี่ยนรูปได้อย่างง่ายดายเหมือนกับreadonly
ฟิลด์ -qualified เช่นเดียวกับreadonly
-qualified fields สามารถเขียนใน constructor ได้เช่นกันด้วยคุณสมบัติ get-only