เขตข้อมูลสาธารณะเปรียบเทียบกับคุณสมบัติอัตโนมัติ


353

เรามักจะบอกว่าเราควรปกป้องการห่อหุ้มด้วยวิธีการ getter และ setter (คุณสมบัติใน C #) สำหรับฟิลด์คลาสแทนที่จะเปิดเผยฟิลด์กับโลกภายนอก

แต่มีหลายครั้งที่เขตข้อมูลอยู่ที่นั่นเพื่อเก็บค่าและไม่ต้องการการคำนวณหรือตั้งค่า สำหรับสิ่งเหล่านี้เราทุกคนจะทำตามหมายเลขนี้:

public class Book
{
    private string _title;

    public string Title
    {
          get{ return _title;  }
          set{ _title = value; }
    }
}

ฉันมีคำสารภาพฉันทนไม่ได้ที่จะเขียนทุกอย่าง (จริง ๆ แล้วมันไม่จำเป็นต้องเขียนมันต้องดูมัน) ดังนั้นฉันจึงไปโกงและใช้พื้นที่สาธารณะ

จากนั้นมาพร้อม C # 3.0 และฉันเห็นว่าพวกเขาเพิ่มคุณสมบัติอัตโนมัติ:

public class Book
{
    public string Title {get; set;} 
}

อันไหนดีกว่าและฉันรู้สึกขอบคุณ แต่จริงๆแล้วอะไรคือสิ่งที่แตกต่างจากการสร้างสนามสาธารณะ

public class Book
{
    public string Title;
}


6
ฉันได้แปลง feild ให้เป็นที่พักเพื่อที่ฉันจะได้ตั้งเบรกพอยต์บนสุนัข
Ian Ringrose

1
ฉันมักจะทำสิ่งใด ๆ ที่ไม่ใช่ทรัพย์สินส่วนตัวเพราะการตระหนักถึงถนนที่ฉันต้องปรับเปลี่ยนเขตข้อมูลให้เป็นทรัพย์สินทำให้เกิดอาการปวดหัวที่ไม่จำเป็น คุณสมบัติฟิลด์และเมธอด พุทโธ่! เรียกความไม่ลงรอยกันที่กัดฉันในอดีต
Steven Wexler

2
propข้อมูลโค้ดทำให้มันรวดเร็วในการสร้างคุณสมบัติ เพียงพิมพ์propจากนั้นแท็บ
Tono Nam

คำตอบ:


175

ในคำถามที่เกี่ยวข้องฉันมีบางเวลาที่ผ่านมามีลิงก์ไปยังการโพสต์ในบล็อกของ Jeff อธิบายความแตกต่างบางอย่าง

คุณสมบัติเทียบกับตัวแปรสาธารณะ

  • การสะท้อนแสงทำงานได้แตกต่างกันไปตามตัวแปรและคุณสมบัติดังนั้นหากคุณใช้การสะท้อนแสงจะใช้คุณสมบัติทั้งหมดได้ง่ายขึ้น
  • คุณไม่สามารถ databind กับตัวแปร
  • การเปลี่ยนตัวแปรเป็นคุณสมบัติเป็นการเปลี่ยนแปลงที่ไม่สิ้นสุด ตัวอย่างเช่น:

    TryGetTitle(out book.Title); // requires a variable

24
"การเปลี่ยนตัวแปรเป็นคุณสมบัติเป็นการเปลี่ยนแปลงที่ไม่สิ้นสุด" หลักสูตรนี้ใช้เฉพาะเมื่อเขียนไลบรารีที่ใช้ซ้ำได้ซึ่งนักพัฒนาส่วนใหญ่ไม่ได้ทำ
Steven

30
นอกจากนี้คุณสมบัติแม้กระทั่งคุณสมบัติอัตโนมัติอาจเป็นเสมือนจริงที่เขตข้อมูลไม่สามารถทำได้ ดังนั้นคลาสฐานสามารถมีการนำไปใช้งานในเขตข้อมูลสำรองอย่างง่าย ๆ ตามที่ผลิตโดยคอมไพเลอร์สำหรับ auto-prop ในขณะที่คลาสที่ได้รับสามารถทำการตรวจสอบเพิ่มเติมหรือตรรกะ / การคำนวณอื่น ๆ
KeithS

28
นอกจากนี้ฟิลด์เป็นตัวแปรและสามารถส่งผ่านโดยการอ้างอิง ( refหรือoutคำหลัก) ในขณะที่คุณสมบัติเป็นคู่ของ accessors และไม่สามารถส่งผ่านโดยการอ้างอิง ตัวอย่างเช่นการbool success = TryGetMyTitle(out myBook.Title);ใช้outจะทำงานกับเขตข้อมูลและไม่สามารถใช้งานได้กับคุณสมบัติ นี่เป็นตัวอย่างที่ชัดเจนว่าทำไมการเปลี่ยนแปลงจากฟิลด์ถึงคุณสมบัติเป็นการเปลี่ยนแปลงที่ไม่สิ้นสุด!
Jeppe Stig Nielsen

2
@ KyleBaran ไม่มันไม่สมเหตุสมผลนักเนื่องจากคุณสมบัติเป็นคู่ของวิธีการเข้าถึงไม่ใช่ตัวแปร สิ่งปกติที่ต้องทำคือการประกาศตัวแปรท้องถิ่น (อาจจะอ่านคุณสมบัติใส่ค่าลงในตัวแปรท้องถิ่น) ผ่านตัวแปรท้องถิ่นเป็นref/ outแล้วตั้งค่าคุณสมบัติให้เป็นค่าที่ตัวแปรท้องถิ่นนั้นมี แต่วิธีการที่เรียกว่าไม่เข้าถึงคุณสมบัตินั้นมันเข้าถึงตัวแปรท้องถิ่นที่คุณทำไว้ที่นั่น
Jeppe Stig Nielsen

5
@theberserker True แม้ว่าใน C # 6 คุณสามารถทำได้public int Foo { get; }ซึ่งจะสร้างคุณสมบัติอัตโนมัติพร้อมฟิลด์สำรองข้อมูลแบบอ่านอย่างเดียว
Michael Stum

83

การเพิกเฉยต่อปัญหา API สิ่งที่ฉันพบว่ามีค่ามากที่สุดเกี่ยวกับการใช้คุณสมบัติคือการแก้ไขข้อบกพร่อง

ดีบักเกอร์ CLR ไม่รองรับจุดพักข้อมูล (ตัวแก้ไขเนทีฟส่วนใหญ่ทำ) ดังนั้นจึงเป็นไปไม่ได้ที่จะกำหนดจุดพักบนการอ่านหรือเขียนของเขตข้อมูลเฉพาะในชั้นเรียน นี่เป็นข้อ จำกัด ในสถานการณ์การดีบักบางอย่าง

เนื่องจากคุณสมบัติถูกนำมาใช้เป็นวิธีการที่บางมากจึงเป็นไปได้ที่จะตั้งค่าเบรกพอยต์ในการอ่านและเขียนของค่าของพวกเขา สิ่งนี้ทำให้พวกเขามีขนาดใหญ่ขึ้นเหนือทุ่ง


2
สิบปีต่อมาเบรกพอยต์ข้อมูลอยู่ที่นี่อย่างน้อยสำหรับ. NET Core :)
39411

72

การเปลี่ยนจากฟิลด์เป็นคุณสมบัติจะทำให้สัญญาแตก (เช่นกำหนดให้ต้องมีการอ้างอิงรหัสทั้งหมดอีกครั้ง) ดังนั้นเมื่อคุณมีจุดโต้ตอบกับคลาสอื่น - สมาชิกสาธารณะ (และได้รับการป้องกันโดยทั่วไป) คุณต้องการวางแผนสำหรับการเติบโตในอนาคต ทำได้โดยใช้คุณสมบัติเสมอ

มันไม่มีอะไรที่จะทำให้มันเป็นสถานที่ให้บริการรถยนต์ในวันนี้และอีก 3 เดือนก็รู้ว่าคุณต้องการที่จะทำให้มันขี้เกียจโหลดและใส่เช็คว่างในช่องว่าง หากคุณใช้ฟิลด์นี่เป็นการเปลี่ยนแปลงคอมไพล์ที่ดีที่สุดและเป็นไปไม่ได้ที่เลวร้ายที่สุดขึ้นอยู่กับว่าใครจะพึ่งพาแอสเซมบลีของคุณ


9
ฉันชอบคำตอบนี้เพราะไม่ได้ใช้คำว่า 'reflection', 'interface' หรือ 'override' (เลวร้ายเกินไปเกี่ยวกับ 'สัญญา')

65

เพียงเพราะไม่มีใครพูดถึงมัน: คุณไม่สามารถกำหนดเขตข้อมูลบนอินเทอร์เฟซ ดังนั้นหากคุณต้องใช้อินเตอร์เฟสเฉพาะซึ่งกำหนดคุณสมบัติบางครั้งคุณสมบัติอัตโนมัติจะเป็นคุณสมบัติที่ดีมาก


1
ฉันจะบอกว่าถ้าคุณต้องการอินเตอร์เฟซที่กำหนดคุณสมบัติมันควรจะเป็นระดับนามธรรม เนื่องจาก c # อนุญาตให้คุณกำหนดคุณสมบัติในส่วนต่อประสานไม่ได้หมายความว่าคุณควรใช้คุณสมบัติเหล่านั้น มันเป็นการออกแบบที่ไม่ดี
Odys

8
@odyodyodys - ฉันไม่แน่ใจว่าฉันยอมรับว่านี่คือการออกแบบที่ไม่ดี โปรดอธิบายเหตุผลของคุณ?
Zaid Masud

4
@odyodyodys ฉันเห็นด้วย zooone9243: Imp จากมุมมองการออกแบบไม่มีความแตกต่างระหว่างการประกาศคุณสมบัติและประกาศคู่ getter / setter (ซึ่งเป็นเรื่องธรรมดาสำหรับอินเตอร์เฟส)
MartinStettner

22
@ zooone9243, + MartinStettner: นั่นคือ 6 เดือนที่ผ่านมาฉันเรียนรู้มากตั้งแต่นั้นมา ฉันสละมันกลับมา :)
ODYS

47

แตกต่างกันมากที่มักจะถูกมองข้ามและไม่ได้กล่าวถึงในคำตอบอื่น ๆ : เอาชนะ คุณสามารถประกาศคุณสมบัติเสมือนและแทนที่พวกเขาในขณะที่คุณไม่สามารถทำเช่นเดียวกันสำหรับเขตข้อมูลสมาชิกสาธารณะ


10

ทุกอย่างเกี่ยวกับการกำหนดรุ่นและความเสถียรของ API ไม่มีความแตกต่างในรุ่น 1 - แต่ต่อมาหากคุณตัดสินใจว่าคุณต้องการทำให้คุณสมบัตินี้มีการตรวจสอบข้อผิดพลาดบางประเภทในเวอร์ชัน 2 คุณไม่จำเป็นต้องเปลี่ยน API ของคุณ - ไม่มีการเปลี่ยนแปลงรหัสใด ๆ นอกจากที่อื่น นิยามของคุณสมบัติ


10

ข้อดีอีกประการของคุณสมบัติที่นำไปใช้โดยอัตโนมัติเหนือเขตข้อมูลสาธารณะคือคุณสามารถกำหนดให้ accessors เป็นส่วนตัวหรือได้รับการป้องกันโดยมอบคลาสของวัตถุที่มีการกำหนดการควบคุมที่ดีกว่าของเขตข้อมูลสาธารณะ


8

publicมีอะไรผิดปกติคือในการทำสนาม แต่จำไว้ว่าการสร้างgetter/setterด้วยprivateเขตข้อมูลนั้นไม่มีการห่อหุ้ม IMO ถ้าคุณไม่สนใจเกี่ยวกับคุณสมบัติอื่น ๆ ของคุณเช่นกันอาจจะทำให้มันPropertypublic


1

หากคุณตัดสินใจในภายหลังเพื่อตรวจสอบว่าชื่อนั้นไม่ซ้ำกันโดยเปรียบเทียบกับคอลเลกชันหรือฐานข้อมูลคุณสามารถทำได้ในคุณสมบัติโดยไม่ต้องเปลี่ยนรหัสใด ๆ ที่ขึ้นอยู่กับมัน

หากคุณไปกับแอตทริบิวต์สาธารณะคุณจะมีความยืดหยุ่นน้อยลง

ความยืดหยุ่นพิเศษโดยไม่ทำลายสัญญาคือสิ่งที่สำคัญที่สุดสำหรับฉันเกี่ยวกับการใช้คุณสมบัติและจนกระทั่งฉันต้องการความยืดหยุ่นจริง ๆ การสร้างอัตโนมัติจะเข้าท่ามากที่สุด


0

สิ่งหนึ่งที่ฉันพบว่ามีประโยชน์มากเช่นเดียวกับรหัสและเหตุผลในการทดสอบทั้งหมดคือถ้าเป็นคุณสมบัติเทียบกับเขตข้อมูลคือ Visual Studio IDE แสดงการอ้างอิงสำหรับคุณสมบัติ แต่ไม่ใช่เขตข้อมูล


0

POV ของฉันหลังจากทำวิจัยแล้ว

  1. การตรวจสอบ
  2. อนุญาตให้แทนที่ accessor เพื่อเปลี่ยนลักษณะการทำงานของคุณสมบัติ
  3. วัตถุประสงค์ในการแก้ไขข้อบกพร่อง เราจะสามารถทราบได้ว่าเมื่อใดและจะมีการเปลี่ยนแปลงคุณสมบัติอย่างไรโดยการตั้งค่าเบรกพอยต์ใน accessor
  4. เราสามารถตั้งค่าฟิลด์ได้เท่านั้น ตัวอย่างเช่นชุดสาธารณะ () และส่วนตัวรับ () นี่เป็นไปไม่ได้กับเขตข้อมูลสาธารณะ

มันทำให้เรามีความเป็นไปได้และความสามารถในการขยายได้มากขึ้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.