ใน C # อะไรทำให้ฟิลด์แตกต่างจากคุณสมบัติและเมื่อใดควรใช้ฟิลด์ใดแทนคุณสมบัติ
ใน C # อะไรทำให้ฟิลด์แตกต่างจากคุณสมบัติและเมื่อใดควรใช้ฟิลด์ใดแทนคุณสมบัติ
คำตอบ:
คุณสมบัติเปิดเผยฟิลด์ ฟิลด์ควร (เกือบตลอดเวลา) ควรเก็บเป็นส่วนตัวในชั้นเรียนและเข้าถึงได้ผ่านทางรับและตั้งค่าคุณสมบัติ พร็อพเพอร์ตี้ให้ระดับของนามธรรมที่ทำให้คุณสามารถเปลี่ยนฟิลด์ในขณะที่ไม่มีผลกระทบต่อวิธีการเข้าถึงจากภายนอกโดยสิ่งต่าง ๆ ที่ใช้คลาสของคุณ
public class MyClass
{
// this is a field. It is private to your class and stores the actual data.
private string _myField;
// this is a property. When accessed it uses the underlying field,
// but only exposes the contract, which will not be affected by the underlying field
public string MyProperty
{
get
{
return _myField;
}
set
{
_myField = value;
}
}
// This is an AutoProperty (C# 3.0 and higher) - which is a shorthand syntax
// used to generate a private field for you
public int AnotherProperty{get;set;}
}
@Kent ชี้ให้เห็นว่าคุณสมบัติไม่จำเป็นต้องมีแค็ปซูลฟิลด์พวกเขาสามารถทำการคำนวณในฟิลด์อื่นหรือใช้เพื่อวัตถุประสงค์อื่น
@GSS ชี้ให้เห็นว่าคุณยังสามารถทำตรรกะอื่น ๆ เช่นการตรวจสอบเมื่อมีการเข้าถึงคุณสมบัติคุณสมบัติอื่นที่มีประโยชน์
string
สัญญาของฉันคือ: กำหนดตัวอักษรใด ๆ ได้สูงสุด ~ 2bil ความยาว หากทรัพย์สินเป็นDateTime
สัญญาของฉันคือ: กำหนดหมายเลขใด ๆ ภายในขีด จำกัด ของ DateTime ซึ่งฉันสามารถค้นหาได้ หากผู้สร้างเพิ่มข้อ จำกัด ให้กับผู้ตั้งค่าข้อ จำกัด เหล่านั้นจะไม่ถูกสื่อสาร แต่ถ้าแทนผู้สร้างการเปลี่ยนแปลงชนิดจากstring
ไปSurname
แล้วระดับนามสกุลใหม่ของพวกเขาสื่อสาร จำกัด และทรัพย์สินที่public Surname LastName
ไม่ได้มีการตรวจสอบการตั้งค่า นอกจากนี้ยังSurname
สามารถนำมาใช้ซ้ำได้
Surname
ในตัวอย่างของฉันสามารถนำกลับมาใช้ใหม่ได้คุณไม่จำเป็นต้องกังวลเกี่ยวกับการคัดลอก / วางการตรวจสอบความถูกต้องเหล่านั้นใน setter คุณสมบัติไปยังสถานที่อื่น ๆ ในรหัส หรือสงสัยว่าการตรวจสอบความถูกต้องของนามสกุลอยู่ในหลาย ๆ ที่หรือไม่หากคุณทำการเปลี่ยนแปลงกฎธุรกิจสำหรับนามสกุล ลองดูลิงค์ที่ฉันโพสต์เกี่ยวกับ Value Objects
หลักการเขียนโปรแกรมเชิงวัตถุบอกว่าการทำงานภายในของชั้นเรียนควรถูกซ่อนไว้จากโลกภายนอก หากคุณเปิดเผยช่องที่คุณกำลังสำคัญเปิดเผยการใช้งานภายในของชั้นเรียน ดังนั้นเราจึงห่อฟิลด์ด้วยคุณสมบัติ (หรือวิธีการในกรณีของ Java) เพื่อให้เราสามารถเปลี่ยนการใช้งานโดยไม่ต้องทำลายรหัสขึ้นอยู่กับเรา การเห็นว่าเราสามารถใส่ตรรกะในคุณสมบัติยังช่วยให้เราสามารถทำการตรวจสอบตรรกะ ฯลฯ หากเราต้องการ C # 3 มีความคิดที่สับสนเกี่ยวกับ autoproperties สิ่งนี้ช่วยให้เราสามารถกำหนด Property และคอมไพเลอร์ C # 3 จะสร้างฟิลด์ส่วนตัวสำหรับเรา
public class Person
{
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public int Age{get;set;} //AutoProperty generates private field for us
}
public int myVar { get; set; }
จริง (และฉันคิดว่ามันเป็นเหตุผล เป็นเวลาอย่างน้อย 50% ของความนิยมที่คำถามนี้ได้รับ)
virtual
ตัวมันเองเป็นส่วนหนึ่งของการเขียนโปรแกรมเชิงวัตถุ
virtual
OOP ต่อทุกครั้ง มันเป็นเครื่องมือที่เปิดใช้งาน polymorphism ซึ่งเป็นหนึ่งในเครื่องมือสำคัญที่ทำให้ ENOPLES OOP มันไม่ได้เป็นของ OOP และของตัวเองและไม่มีอะไรโดยเนื้อแท้ OOP เกี่ยวกับ autoproperty สาธารณะ ฉันจะไม่นับสิ่งต่าง ๆ เช่นภาพสะท้อนหรือการบันทึกข้อมูล OOP ที่เกี่ยวข้องเช่นกัน โดยปกติฉันจะไม่พูดถึงมันมากนัก แต่คำตอบที่กล่าวถึงหลักการ OO เป็นแรงผลักดันที่อยู่เบื้องหลังตัวอย่างโค้ดและฉันไม่เห็นด้วย
ความแตกต่างที่สำคัญคืออินเตอร์เฟสสามารถมีคุณสมบัติได้ แต่ไม่ใช่ฟิลด์ สิ่งนี้สำหรับฉันขีดเส้นใต้ว่าควรใช้คุณสมบัติเพื่อกำหนดอินเทอร์เฟซสาธารณะของคลาสในขณะที่ฟิลด์นั้นมีไว้เพื่อใช้ในการทำงานส่วนตัวภายในของคลาส ตามกฎแล้วฉันไม่ค่อยสร้างเขตข้อมูลสาธารณะและในทำนองเดียวกันฉันไม่ค่อยสร้างคุณสมบัติที่ไม่ใช่แบบสาธารณะ
ฉันจะให้คุณสองสามตัวอย่างของการใช้คุณสมบัติที่อาจเปลี่ยนเกียร์:
ใช้คุณสมบัติคุณสามารถเพิ่มเหตุการณ์เมื่อค่าของคุณสมบัติมีการเปลี่ยนแปลง (aka. PropertyChangedEvent) หรือก่อนที่ค่าจะเปลี่ยนเพื่อรองรับการยกเลิก
ไม่สามารถทำได้ด้วยช่อง (เข้าถึงโดยตรงไปยัง)
public class Person {
private string _name;
public event EventHandler NameChanging;
public event EventHandler NameChanged;
public string Name{
get
{
return _name;
}
set
{
OnNameChanging();
_name = value;
OnNameChanged();
}
}
private void OnNameChanging(){
NameChanging?.Invoke(this,EventArgs.Empty);
}
private void OnNameChanged(){
NameChanged?.Invoke(this,EventArgs.Empty);
}
}
เนื่องจากหลายคนได้อธิบายกับผู้เชี่ยวชาญด้านเทคนิคและข้อเสียของProperties
และField
ถึงเวลาที่จะได้รับตัวอย่างเรียลไทม์
1. คุณสมบัติช่วยให้คุณตั้งค่าระดับการเข้าถึงแบบอ่านอย่างเดียว
พิจารณากรณีdataTable.Rows.Count
และdataTable.Columns[i].Caption
. พวกเขามาจากชั้นเรียนDataTable
และเป็นที่เปิดเผยแก่เรา ความแตกต่างในระดับการเข้าถึงข้อมูลสำหรับพวกเขาคือเราไม่สามารถกำหนดค่าเป็นdataTable.Rows.Count
แต่เราสามารถอ่านและเขียนdataTable.Columns[i].Caption
ได้ เป็นไปได้ที่ผ่านField
? ไม่มี !!! สิ่งนี้สามารถทำได้ด้วยProperties
เท่านั้น
public class DataTable
{
public class Rows
{
private string _count;
// This Count will be accessable to us but have used only "get" ie, readonly
public int Count
{
get
{
return _count;
}
}
}
public class Columns
{
private string _caption;
// Used both "get" and "set" ie, readable and writable
public string Caption
{
get
{
return _caption;
}
set
{
_caption = value;
}
}
}
}
2. คุณสมบัติใน PropertyGrid
คุณอาจทำงานกับButton
ใน Visual Studio คุณสมบัติของมันจะแสดงในสิ่งที่PropertyGrid
คล้ายText
กันName
ฯลฯ เมื่อเราลากและวางปุ่มและเมื่อเราคลิกคุณสมบัติมันจะค้นหาคลาสButton
และตัวกรองโดยอัตโนมัติProperties
และแสดงว่าในPropertyGrid
(ซึ่งPropertyGrid
จะไม่แสดงField
แม้ว่าจะเป็นสาธารณะ)
public class Button
{
private string _text;
private string _name;
private string _someProperty;
public string Text
{
get
{
return _text;
}
set
{
_text = value;
}
}
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
[Browsable(false)]
public string SomeProperty
{
get
{
return _someProperty;
}
set
{
_someProperty= value;
}
}
ในPropertyGrid
, คุณสมบัติName
และText
จะแสดง SomeProperty
แต่ไม่ ทำไม??? เนื่องจากคุณสมบัติสามารถรับคุณสมบัติได้ มันจะไม่แสดงในกรณีที่[Browsable(false)]
เป็นเท็จ
3. สามารถดำเนินการคำสั่งภายในคุณสมบัติ
public class Rows
{
private string _count;
public int Count
{
get
{
return CalculateNoOfRows();
}
}
public int CalculateNoOfRows()
{
// Calculation here and finally set the value to _count
return _count;
}
}
4. สามารถใช้คุณสมบัติได้เฉพาะในแหล่งข้อมูลการผูก
Binding Sourceช่วยให้เราลดจำนวนบรรทัดของรหัส ยังไม่ได้รับการยอมรับจากFields
BindingSource
เราควรใช้Properties
เพื่อสิ่งนั้น
5. โหมดแก้ไขข้อบกพร่อง
พิจารณาว่าเรากำลังใช้Field
เพื่อเก็บค่า ในบางจุดเราจำเป็นต้องตรวจแก้จุดบกพร่องและตรวจสอบว่าค่าที่ได้รับเป็นโมฆะสำหรับเขตข้อมูลนั้น มันจะเป็นเรื่องยากที่จะทำซึ่งมีจำนวนบรรทัดของรหัสที่มีมากกว่า 1000 ในสถานการณ์เช่นนี้เราสามารถใช้และสามารถตั้งค่าการแก้ปัญหาภายในโหมดProperty
Property
public string Name
{
// Can set debug mode inside get or set
get
{
return _name;
}
set
{
_name = value;
}
}
ฟิลด์เป็นตัวแปรที่มีการประกาศโดยตรงในชั้นเรียนหรือ struct คลาสหรือโครงสร้างอาจมีฟิลด์อินสแตนซ์หรือฟิลด์สแตติกหรือทั้งสองอย่าง โดยทั่วไปแล้วคุณควรใช้เขตข้อมูลเฉพาะสำหรับตัวแปรที่มีการเข้าถึงส่วนตัวหรือการป้องกัน ข้อมูลที่คลาสของคุณเปิดเผยถึงรหัสลูกค้าควรได้รับการจัดเตรียมผ่านวิธีการคุณสมบัติและตัวทำดัชนี โดยใช้โครงสร้างเหล่านี้สำหรับการเข้าถึงเขตข้อมูลภายในโดยอ้อมคุณสามารถป้องกันค่าอินพุตที่ไม่ถูกต้อง
คุณสมบัติเป็นสมาชิกที่ให้กลไกที่มีความยืดหยุ่นในการอ่านเขียนหรือการคำนวณมูลค่าของข้อมูลส่วนตัว คุณสมบัติสามารถใช้เป็นหากพวกเขาเป็นประชาชนสมาชิกข้อมูล แต่พวกเขาเป็นจริงวิธีการพิเศษที่เรียกว่าaccessors ทำให้สามารถเข้าถึงข้อมูลได้ง่ายและยังช่วยส่งเสริมความปลอดภัยและความยืดหยุ่นของวิธีการต่างๆ คุณสมบัติช่วยให้คลาสเปิดเผยวิธีการรับและการตั้งค่าสาธารณะในขณะที่ซ่อนการใช้งานหรือรหัสยืนยัน get access accessor ใช้เพื่อส่งคืนค่าคุณสมบัติและชุด access access ถูกใช้เพื่อกำหนดค่าใหม่
คุณสมบัติมีข้อได้เปรียบหลักในการอนุญาตให้คุณเปลี่ยนวิธีการเข้าถึงข้อมูลบนวัตถุโดยไม่ทำลายส่วนต่อประสานสาธารณะ ตัวอย่างเช่นถ้าคุณต้องการเพิ่มการตรวจสอบพิเศษหรือเปลี่ยนเขตข้อมูลที่เก็บไว้ในการคำนวณคุณสามารถทำได้อย่างง่ายดายหากคุณเปิดเผยเขตข้อมูลเป็นคุณสมบัติครั้งแรก หากคุณเพิ่งเปิดดูฟิลด์โดยตรงคุณจะต้องเปลี่ยนอินเทอร์เฟซสาธารณะของชั้นเรียนของคุณเพื่อเพิ่มฟังก์ชั่นใหม่ การเปลี่ยนแปลงนั้นจะทำให้ลูกค้าที่มีอยู่เดิมต้องการให้พวกเขาคอมไพล์ใหม่ก่อนจึงจะสามารถใช้รหัสรุ่นใหม่ของคุณได้
หากคุณเขียนไลบรารีคลาสที่ออกแบบมาเพื่อการใช้งานที่กว้างขวาง (เช่น. NET Framework ซึ่งถูกใช้โดยผู้คนหลายล้านคน) นั่นอาจเป็นปัญหาได้ อย่างไรก็ตามหากคุณกำลังเขียนคลาสที่ใช้ภายในโค้ดเบสขนาดเล็ก (พูดว่า <= 50 K บรรทัด) มันไม่ใช่เรื่องใหญ่จริง ๆ เพราะไม่มีใครจะได้รับผลกระทบจากการเปลี่ยนแปลงของคุณ ในกรณีนั้นจริงๆมันเป็นเพียงการตั้งค่าส่วนตัว
คุณสมบัติรองรับการเข้าถึงแบบอสมมาตรเช่นคุณสามารถมีทั้งตัวรับและตัวตั้งค่าหรือเพียงหนึ่งในสองตัว คุณสมบัติในทำนองเดียวกันสนับสนุนการเข้าถึงส่วนบุคคลสำหรับ getter / setter เขตข้อมูลมีความสมมาตรอยู่เสมอนั่นคือคุณสามารถรับและตั้งค่าได้ตลอดเวลา ข้อยกเว้นนี้คือฟิลด์แบบอ่านอย่างเดียวซึ่งไม่สามารถตั้งค่าได้อย่างชัดเจนหลังจากการกำหนดค่าเริ่มต้น
คุณสมบัติอาจทำงานเป็นเวลานานมีผลข้างเคียงและอาจทำให้เกิดข้อยกเว้น เขตข้อมูลมีความรวดเร็วโดยไม่มีผลข้างเคียงและจะไม่มีข้อยกเว้น เนื่องจากผลข้างเคียงคุณสมบัติอาจส่งคืนค่าที่แตกต่างกันสำหรับการโทรแต่ละครั้ง (เช่นในกรณีของ DateTime.Now เช่น DateTime.Now ไม่เท่ากับ DateTime.Now เสมอ) ฟิลด์คืนค่าเดิมเสมอ
ฟิลด์อาจใช้สำหรับพารามิเตอร์ out / ref คุณสมบัติอาจไม่ คุณสมบัติสนับสนุนตรรกะเพิ่มเติม - ซึ่งสามารถใช้เพื่อดำเนินการโหลดแบบสันหลังยาวในหมู่สิ่งอื่น ๆ
คุณสมบัติสนับสนุนระดับของนามธรรมโดยการห่อหุ้มสิ่งที่มันหมายถึงการได้รับ / การตั้งค่า
ใช้คุณสมบัติในกรณีส่วนใหญ่ / ทั้งหมด แต่พยายามหลีกเลี่ยงผลข้างเคียง
ในพื้นหลังคุณสมบัติจะรวบรวมเป็นวิธีการ ดังนั้นName
คุณสมบัติเรียบเรียงและget_Name()
set_Name(string value)
คุณสามารถเห็นสิ่งนี้หากคุณศึกษารหัสรวบรวม ดังนั้นจึงมีค่าใช้จ่ายเล็ก ๆ (มาก) ของประสิทธิภาพเมื่อใช้งาน โดยปกติคุณจะใช้คุณสมบัติเสมอหากคุณเปิดเผยฟิลด์ไปยังภายนอกและคุณมักจะใช้ภายในหากคุณต้องการตรวจสอบความถูกต้องของค่า
เมื่อคุณต้องการให้ตัวแปรส่วนตัว (ฟิลด์) ของคุณสามารถเข้าถึงวัตถุของคลาสจากคลาสอื่นคุณต้องสร้างคุณสมบัติสำหรับตัวแปรเหล่านั้น
ตัวอย่างเช่นถ้าฉันมีตัวแปรชื่อเป็น "id" และ "name" ซึ่งเป็นส่วนตัว แต่อาจมีสถานการณ์ที่ตัวแปรนี้จำเป็นสำหรับการดำเนินการอ่าน / เขียนนอกชั้นเรียน ในสถานการณ์นั้นคุณสมบัติสามารถช่วยให้ฉันรับตัวแปรนั้นเพื่ออ่าน / เขียนขึ้นอยู่กับการรับ / กำหนดที่กำหนดไว้สำหรับคุณสมบัติ คุณสมบัติสามารถเป็นแบบอ่านอย่างเดียว / เขียนอย่างเดียว / อ่านได้ทั้งสองอย่าง
นี่คือตัวอย่าง
class Employee
{
// Private Fields for Employee
private int id;
private string name;
//Property for id variable/field
public int EmployeeId
{
get
{
return id;
}
set
{
id = value;
}
}
//Property for name variable/field
public string EmployeeName
{
get
{
return name;
}
set
{
name = value;
}
}
}
class MyMain
{
public static void Main(string [] args)
{
Employee aEmployee = new Employee();
aEmployee.EmployeeId = 101;
aEmployee.EmployeeName = "Sundaran S";
}
}
คำถามที่สองที่นี่ "เมื่อควรสนามนำมาใช้แทนของทรัพย์สินหรือไม่?" สัมผัสเพียงสั้น ๆ ในคำตอบอื่น ๆ นี้และครับอันนี้เกินไปแต่ไม่ได้รายละเอียดมากจริงๆ
โดยทั่วไปแล้วคำตอบอื่น ๆ ทั้งหมดเป็นแบบเฉพาะจุดเกี่ยวกับการออกแบบที่ดี: ชอบการเปิดเผยคุณสมบัติมากกว่าการเปิดเผยฟิลด์ ในขณะที่คุณอาจจะไม่สม่ำเสมอพบว่าตัวเองพูดว่า "ว้าว, จินตนาการเท่าใดสิ่งที่เลวร้ายจะเป็นถ้าฉันได้ทำนี้ฟิลด์แทนของสถานที่ให้บริการ" ก็มากหายากมากขึ้นที่จะคิดว่าสถานการณ์ที่คุณจะพูดว่า "ว้าวที่ ขอบคุณพระเจ้าที่ฉันใช้ฟิลด์ที่นี่แทนอสังหาริมทรัพย์ "
แต่มีข้อดีอย่างหนึ่งที่เขตข้อมูลมีคุณสมบัติมากกว่าและนั่นคือความสามารถในการใช้เป็นพารามิเตอร์ "ref" / "out" สมมติว่าคุณมีวิธีการที่มีลายเซ็นดังต่อไปนี้:
public void TransformPoint(ref double x, ref double y);
และสมมติว่าคุณต้องการใช้วิธีการนั้นในการแปลงอาเรย์ที่สร้างขึ้นเช่นนี้
System.Windows.Point[] points = new Point[1000000];
Initialize(points);
นี่ฉันคิดว่าวิธีที่เร็วที่สุดที่จะทำเพราะXและYเป็นคุณสมบัติ:
for (int i = 0; i < points.Length; i++)
{
double x = points[i].X;
double y = points[i].Y;
TransformPoint(ref x, ref y);
points[i].X = x;
points[i].Y = y;
}
และนั่นจะเป็นสิ่งที่ดีทีเดียว! ถ้าคุณไม่มีการวัดที่พิสูจน์เป็นอย่างอื่นไม่มีเหตุผลที่จะทำให้เหม็น แต่ฉันเชื่อว่ามันไม่ได้รับประกันว่าจะเร็วเท่านี้:
internal struct MyPoint
{
internal double X;
internal double Y;
}
// ...
MyPoint[] points = new MyPoint[1000000];
Initialize(points);
// ...
for (int i = 0; i < points.Length; i++)
{
TransformPoint(ref points[i].X, ref points[i].Y);
}
การทำการวัดบางอย่างด้วยตัวเองรุ่นที่มีเขตข้อมูลใช้เวลาประมาณ 61% ของเวลาเป็นรุ่นที่มีคุณสมบัติ (.NET 4.6, Windows 7, x64, โหมดการเปิดตัวโดยไม่มีการเชื่อมต่อดีบักเกอร์) ยิ่งTransformPoint
วิธีการมีราคาแพงเท่าใดก็ยิ่งมีความแตกต่างน้อยลงเท่านั้น หากต้องการทำซ้ำด้วยตัวคุณเองให้รันด้วยบรรทัดแรกที่แสดงความคิดเห็นและไม่ได้แสดงความคิดเห็น
แม้ว่าจะไม่มีประโยชน์ด้านประสิทธิภาพสำหรับข้างต้น แต่ก็มีสถานที่อื่นที่สามารถใช้พารามิเตอร์ ref และ out อาจเป็นประโยชน์เช่นเมื่อเรียกเมธอดตระกูล InterlockedหรือVolatile หมายเหตุ: ในกรณีนี้เป็นสิ่งใหม่สำหรับคุณความผันผวนนั้นเป็นวิธีการที่จะได้รับพฤติกรรมเดียวกับที่ให้ไว้โดยvolatile
คำหลัก เช่นนี้volatile
มันไม่ได้แก้ปัญหาความปลอดภัยของเธรดทั้งหมดอย่างน่าอัศจรรย์อย่างที่ชื่อบอกไว้
ฉันไม่ต้องการที่จะดูเหมือนว่าฉันกำลังเรียกร้องให้คุณไป "โอ้ฉันควรเริ่มเปิดเผยฟิลด์แทนคุณสมบัติ" ประเด็นก็คือถ้าคุณจำเป็นต้องใช้สมาชิกเหล่านี้เป็นประจำในการโทรที่ใช้พารามิเตอร์ "ref" หรือ "out" โดยเฉพาะอย่างยิ่งกับสิ่งที่อาจเป็นประเภทค่าแบบง่ายที่ไม่น่าจะต้องการองค์ประกอบที่มีมูลค่าเพิ่มใด ๆ อาร์กิวเมนต์สามารถทำได้
แม้ว่าเขตข้อมูลและคุณสมบัติจะมีลักษณะคล้ายกัน แต่มีองค์ประกอบทางภาษาที่แตกต่างกัน 2 อย่าง
เขตข้อมูลเป็นกลไกเดียวที่จะเก็บข้อมูลในระดับชั้นเรียน ฟิลด์เป็นตัวแปรแนวคิดที่ขอบเขตของคลาส หากคุณต้องการจัดเก็บข้อมูลบางอย่างไปยังอินสแตนซ์ของคลาส (วัตถุ) ของคุณคุณต้องใช้ฟิลด์ ไม่มีทางเลือกอื่น คุณสมบัติไม่สามารถจัดเก็บข้อมูลใด ๆ แม้ว่ามันอาจดูเหมือนพวกเขาสามารถทำได้ เห็นเสียงร้อง
ในทางกลับกันคุณสมบัติไม่เคยเก็บข้อมูล พวกเขาเป็นเพียงคู่ของวิธีการ (รับและตั้งค่า) ที่สามารถเรียก syntactically ในลักษณะที่คล้ายกันเป็นเขตข้อมูลและในกรณีส่วนใหญ่พวกเขาเข้าถึงเขตข้อมูล (สำหรับอ่านหรือเขียน) ซึ่งเป็นแหล่งที่มาของความสับสนบางอย่าง แต่เนื่องจากวิธีการคุณสมบัติ (ด้วยข้อ จำกัด บางอย่างเช่นต้นแบบถาวร) วิธีการทั่วไป C # พวกเขาสามารถทำสิ่งที่วิธีการปกติสามารถทำได้ มันหมายความว่าพวกเขาสามารถมี 1,000 บรรทัดของรหัสพวกเขาสามารถโยนข้อยกเว้นเรียกวิธีการอื่นได้แม้เสมือนนามธรรมหรือแทนที่ สิ่งที่ทำให้คุณสมบัติพิเศษคือความจริงที่ว่า C # คอมไพเลอร์เก็บเมตาดาต้าพิเศษบางอย่างลงในแอสเซมบลีที่สามารถใช้เพื่อค้นหาคุณสมบัติเฉพาะ - คุณลักษณะที่ใช้กันอย่างแพร่หลาย
รับและตั้งค่าวิธีการทรัพย์สินมีต้นแบบต่อไปนี้
PROPERTY_TYPE get();
void set(PROPERTY_TYPE value);
ดังนั้นหมายความว่าคุณสมบัติสามารถ 'จำลอง' โดยการกำหนดเขตข้อมูลและวิธีการที่สอดคล้องกัน 2 วิธี
class PropertyEmulation
{
private string MSomeValue;
public string GetSomeValue()
{
return(MSomeValue);
}
public void SetSomeValue(string value)
{
MSomeValue=value;
}
}
การจำลองคุณสมบัติดังกล่าวเป็นเรื่องปกติสำหรับภาษาการเขียนโปรแกรมที่ไม่สนับสนุนคุณสมบัติ - เช่น C ++ มาตรฐาน ใน C # นั้นคุณควรต้องการคุณสมบัติเป็นวิธีการเข้าถึงเขตข้อมูลของคุณ
เนื่องจากมีเพียงเขตข้อมูลเท่านั้นที่สามารถจัดเก็บข้อมูลได้หมายความว่ามีคลาสของเขตข้อมูลเพิ่มเติมมากขึ้นวัตถุหน่วยความจำของคลาสดังกล่าวจะหมด ในทางตรงกันข้ามการเพิ่มคุณสมบัติใหม่เข้าไปในคลาสไม่ได้ทำให้วัตถุของคลาสนั้นใหญ่ขึ้น นี่คือตัวอย่าง
class OneHundredFields
{
public int Field1;
public int Field2;
...
public int Field100;
}
OneHundredFields Instance=new OneHundredFields() // Variable 'Instance' consumes 100*sizeof(int) bytes of memory.
class OneHundredProperties
{
public int Property1
{
get
{
return(1000);
}
set
{
// Empty.
}
}
public int Property2
{
get
{
return(1000);
}
set
{
// Empty.
}
}
...
public int Property100
{
get
{
return(1000);
}
set
{
// Empty.
}
}
}
OneHundredProperties Instance=new OneHundredProperties() // !!!!! Variable 'Instance' consumes 0 bytes of memory. (In fact a some bytes are consumed becasue every object contais some auxiliarity data, but size doesn't depend on number of properties).
แม้ว่าวิธีการของคุณสมบัติสามารถทำสิ่งใดก็ได้ในกรณีส่วนใหญ่พวกเขาใช้เป็นวิธีการเข้าถึงเขตข้อมูลของวัตถุ หากคุณต้องการให้ฟิลด์อื่นสามารถเข้าถึงคลาสอื่นได้คุณสามารถทำได้ 2 วิธี
นี่คือคลาสที่ใช้ฟิลด์สาธารณะ
class Name
{
public string FullName;
public int YearOfBirth;
public int Age;
}
Name name=new Name();
name.FullName="Tim Anderson";
name.YearOfBirth=1979;
name.Age=40;
ในขณะที่รหัสถูกต้องสมบูรณ์แบบจากมุมมองการออกแบบ แต่ก็มีข้อเสียหลายประการ เนื่องจากเขตข้อมูลสามารถเป็นทั้งอ่านและเขียนคุณไม่สามารถป้องกันผู้ใช้จากการเขียนไปยังเขตข้อมูล คุณสามารถใช้readonly
คำหลัก แต่ด้วยวิธีนี้คุณต้องเริ่มต้นฟิลด์แบบอ่านอย่างเดียวเท่านั้นในตัวสร้าง ยิ่งไปกว่านั้นไม่มีอะไรป้องกันไม่ให้คุณเก็บค่าที่ไม่ถูกต้องลงในช่องของคุณ
name.FullName=null;
name.YearOfBirth=2200;
name.Age=-140;
รหัสนั้นถูกต้องการมอบหมายทั้งหมดจะถูกดำเนินการแม้ว่าจะไร้เหตุผลก็ตาม Age
มีค่าลบYearOfBirth
อยู่ไกลในอนาคตและไม่ตรงกับอายุและFullName
เป็นโมฆะ ด้วยฟิลด์ที่คุณไม่สามารถป้องกันผู้ใช้ในclass Name
การทำผิดพลาดดังกล่าว
นี่คือรหัสที่มีคุณสมบัติที่แก้ไขปัญหาเหล่านี้
class Name
{
private string MFullName="";
private int MYearOfBirth;
public string FullName
{
get
{
return(MFullName);
}
set
{
if (value==null)
{
throw(new InvalidOperationException("Error !"));
}
MFullName=value;
}
}
public int YearOfBirth
{
get
{
return(MYearOfBirth);
}
set
{
if (MYearOfBirth<1900 || MYearOfBirth>DateTime.Now.Year)
{
throw(new InvalidOperationException("Error !"));
}
MYearOfBirth=value;
}
}
public int Age
{
get
{
return(DateTime.Now.Year-MYearOfBirth);
}
}
public string FullNameInUppercase
{
get
{
return(MFullName.ToUpper());
}
}
}
คลาสที่อัปเดตแล้วมีข้อดีดังต่อไปนี้
FullName
และYearOfBirth
มีการตรวจสอบค่าที่ไม่ถูกต้องAge
ไม่สามารถเขียนได้ มัน callculated จากYearOfBirth
และปีปัจจุบันFullNameInUppercase
แปลงFullName
เป็นกรณีบน นี่เป็นตัวอย่างเล็กน้อยของการใช้งานคุณสมบัติที่มีการใช้คุณสมบัติทั่วไปเพื่อแสดงค่าของฟิลด์ในรูปแบบที่เหมาะสมกับผู้ใช้มากขึ้น - ตัวอย่างเช่นการใช้ภาษาปัจจุบันกับตัวเลขเฉพาะของDateTime
รูปแบบข้างนี้คุณสมบัติสามารถกำหนดเป็นเสมือนหรือแทนที่ - เพราะพวกเขาเป็นวิธีการ. NET ปกติ กฎเดียวกันนี้ใช้สำหรับวิธีการคุณสมบัติเช่นเดียวกับวิธีการปกติ
C # ยังสนับสนุนตัวสร้างดัชนีซึ่งเป็นคุณสมบัติที่มีพารามิเตอร์ดัชนีในวิธีการคุณสมบัติ นี่คือตัวอย่าง
class MyList
{
private string[] MBuffer;
public MyList()
{
MBuffer=new string[100];
}
public string this[int Index]
{
get
{
return(MBuffer[Index]);
}
set
{
MBuffer[Index]=value;
}
}
}
MyList List=new MyList();
List[10]="ABC";
Console.WriteLine(List[10]);
เนื่องจาก C # 3.0 ช่วยให้คุณสามารถกำหนดคุณสมบัติอัตโนมัติ นี่คือตัวอย่าง
class AutoProps
{
public int Value1
{
get;
set;
}
public int Value2
{
get;
set;
}
}
แม้ว่าจะclass AutoProps
มีคุณสมบัติเท่านั้น (หรือดูเหมือนว่า) มันสามารถเก็บค่า 2 และขนาดของวัตถุของคลาสนี้เท่ากับsizeof(Value1)+sizeof(Value2)
= 4 + 4 = 8 ไบต์
เหตุผลนี้ง่าย เมื่อคุณกำหนดคุณสมบัติอัตโนมัติคอมไพเลอร์ C # จะสร้างรหัสอัตโนมัติที่มีเขตข้อมูลที่ซ่อนอยู่และคุณสมบัติที่มีวิธีการเข้าถึงเขตข้อมูลที่ซ่อนอยู่นี้ นี่คือการรวบรวมรหัสผลิต
นี่คือรหัสที่ILSpyสร้างขึ้นจากการประกอบที่รวบรวม คลาสมีฟิลด์และคุณสมบัติที่ซ่อนอยู่ที่สร้างขึ้น
internal class AutoProps
{
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int <Value1>k__BackingField;
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int <Value2>k__BackingField;
public int Value1
{
[CompilerGenerated]
get
{
return <Value1>k__BackingField;
}
[CompilerGenerated]
set
{
<Value1>k__BackingField = value;
}
}
public int Value2
{
[CompilerGenerated]
get
{
return <Value2>k__BackingField;
}
[CompilerGenerated]
set
{
<Value2>k__BackingField = value;
}
}
}
ดังนั้นอย่างที่คุณเห็นคอมไพเลอร์ยังคงใช้เขตข้อมูลเพื่อเก็บค่า - เนื่องจากเขตข้อมูลเป็นวิธีเดียวที่จะเก็บค่าลงในวัตถุ
ดังที่คุณเห็นแม้ว่าคุณสมบัติและเขตข้อมูลจะมีไวยากรณ์การใช้งานที่คล้ายคลึงกัน แต่เป็นแนวคิดที่แตกต่างกันมาก แม้ว่าคุณจะใช้คุณสมบัติอัตโนมัติหรือเหตุการณ์ - เขตข้อมูลที่ซ่อนอยู่จะถูกสร้างขึ้นโดยคอมไพเลอร์ที่จัดเก็บข้อมูลจริง
หากคุณต้องการทำให้ค่าฟิลด์สามารถเข้าถึงได้จากโลกภายนอก (ผู้ใช้ในชั้นเรียนของคุณ) อย่าใช้ฟิลด์สาธารณะหรือเขตข้อมูลที่มีการป้องกัน ฟิลด์ควรถูกทำเครื่องหมายเป็นส่วนตัวเสมอ คุณสมบัติช่วยให้คุณสามารถตรวจสอบค่าการจัดรูปแบบการแปลง ฯลฯ และโดยทั่วไปจะทำให้รหัสของคุณปลอดภัยอ่านและขยายได้มากขึ้นสำหรับการแก้ไขในอนาคต
นอกจากนี้คุณสมบัติช่วยให้คุณใช้ตรรกะเมื่อตั้งค่า
ดังนั้นคุณสามารถบอกได้ว่าคุณต้องการตั้งค่าให้เป็นเขตข้อมูลจำนวนเต็มเท่านั้นหากค่ามากกว่า x มิฉะนั้นจะเกิดข้อยกเว้น
คุณสมบัติที่มีประโยชน์จริงๆ
หากคุณกำลังจะใช้เธรดพื้นฐานคุณจำเป็นต้องใช้ฟิลด์ คุณสมบัติสามารถทำลายรหัสเธรดของคุณ นอกเหนือจากนั้นสิ่งที่คอรีกล่าวถูกต้อง
(นี่ควรเป็นความคิดเห็นจริงๆ แต่ฉันไม่สามารถโพสต์ความคิดเห็นได้ดังนั้นโปรดแก้ตัวถ้ามันไม่เหมาะสมกับโพสต์)
ฉันเคยทำงานในสถานที่ซึ่งแนวทางปฏิบัติที่แนะนำคือใช้เขตข้อมูลสาธารณะแทนคุณสมบัติเมื่อ def คุณสมบัติที่เทียบเท่าจะเพิ่งเข้าถึงเขตข้อมูลเช่นเดียวกับใน:
get { return _afield; }
set { _afield = value; }
เหตุผลของพวกเขาคือฟิลด์สาธารณะสามารถเปลี่ยนเป็นทรัพย์สินได้ในภายหลังในอนาคตหากจำเป็น ในเวลานั้นฉันรู้สึกแปลกเล็กน้อย ตัดสินโดยโพสต์เหล่านี้ดูเหมือนว่าไม่มากที่นี่จะเห็นด้วย คุณอาจจะพูดอะไรเพื่อลองเปลี่ยนสิ่งต่างๆ
แก้ไข: ฉันควรเพิ่มว่ารหัสฐานทั้งหมด ณ ที่นี้ถูกรวบรวมในเวลาเดียวกันดังนั้นพวกเขาอาจคิดว่าการเปลี่ยนอินเทอร์เฟซสาธารณะของคลาส (โดยการเปลี่ยนเขตข้อมูลสาธารณะเป็นคุณสมบัติ) ไม่มีปัญหา
ในทางเทคนิคแล้วฉันไม่คิดว่ามีความแตกต่างเนื่องจากคุณสมบัติเป็นเพียงการล้อมรอบฟิลด์ที่สร้างโดยผู้ใช้หรือสร้างโดยคอมไพเลอร์โดยอัตโนมัติวัตถุประสงค์ของคุณสมบัติคือการบังคับใช้การห่อหุ้มและนำเสนอคุณสมบัติที่มีน้ำหนักเบา เป็นเพียงการปฏิบัติที่ไม่ดีในการประกาศฟิลด์ในฐานะสาธารณะ แต่ไม่มีปัญหาใด ๆ
ฟิลด์เป็นตัวแปรสมาชิกสามัญหรืออินสแตนซ์สมาชิกของคลาส คุณสมบัติเป็นนามธรรมที่จะได้รับและการตั้งค่าของพวกเขา คุณสมบัติจะเรียกว่า accessors ด้วยเนื่องจากพวกเขาเสนอวิธีการเปลี่ยนและดึงข้อมูลในฟิลด์ถ้าคุณเปิดเผยฟิลด์ในคลาสเป็นแบบส่วนตัว โดยทั่วไปคุณควรประกาศตัวแปรสมาชิกของคุณเป็นส่วนตัวจากนั้นประกาศหรือกำหนดคุณสมบัติสำหรับพวกเขา
class SomeClass
{
int numbera; //Field
//Property
public static int numbera { get; set;}
}
คุณสมบัติห่อหุ้มฟิลด์ซึ่งช่วยให้คุณสามารถดำเนินการประมวลผลเพิ่มเติมเกี่ยวกับค่าที่จะตั้งหรือดึงข้อมูล โดยทั่วไปแล้วจะใช้งานเกินขนาดหากคุณจะไม่ทำอะไรก่อนหรือหลังการประมวลผลบนค่าของฟิลด์
IMO, คุณสมบัติเป็นเพียง "SetXXX ()" "GetXXX ()" ฟังก์ชั่น / วิธีการ / การเชื่อมต่อคู่ที่เราใช้ก่อนหน้านี้ แต่พวกเขาจะกระชับและสง่างามมากขึ้น
การตั้งค่าฟิลด์ส่วนตัวตามธรรมเนียมผ่าน getter และ setter เพื่อประโยชน์ของรหัสน้อยคุณสามารถใช้คุณสมบัติในการตั้งค่าเขตข้อมูลแทน
เมื่อคุณมีคลาสซึ่งก็คือ "รถยนต์" คุณสมบัติเป็นสีรูปร่าง ..
โดยที่ฟิลด์เป็นตัวแปรที่กำหนดไว้ภายในขอบเขตของคลาส
จาก Wikipedia - โปรแกรมเชิงวัตถุ :
การเขียนโปรแกรมเชิงวัตถุ (OOP) เป็นกระบวนทัศน์การเขียนโปรแกรมตามแนวคิดของ "วัตถุ" ซึ่งเป็นโครงสร้างข้อมูลที่มีข้อมูลในรูปแบบของเขตข้อมูลมักจะเรียกว่าคุณลักษณะ; และรหัสในรูปแบบของวิธีการที่รู้จักกันมักจะเป็นวิธีการ (เน้นเพิ่ม)
คุณสมบัติเป็นส่วนหนึ่งของพฤติกรรมของวัตถุ แต่ถูกออกแบบมาเพื่อให้ผู้ใช้ของวัตถุมีภาพลวงตา / นามธรรมของการทำงานกับข้อมูลของวัตถุ
การออกแบบฟิลด์ของฉันคือฟิลด์ต้องแก้ไขโดยผู้ปกครองเท่านั้นดังนั้นคลาส ส่งผลให้ตัวแปรกลายเป็นแบบส่วนตัวจากนั้นจะสามารถให้สิทธิ์ในการอ่านคลาส / วิธีการด้านนอกฉันผ่านระบบทรัพย์สินที่มีเพียงรับ เขตข้อมูลจะถูกเรียกคืนโดยคุณสมบัติและอ่านอย่างเดียว! ถ้าคุณต้องการแก้ไขมันคุณจะต้องผ่านวิธีการ (ตัวอย่างเช่น Constructor) และฉันพบว่าด้วยวิธีนี้ที่ทำให้คุณปลอดภัยเราสามารถควบคุมรหัสของเราได้ดีขึ้นเพราะเรา "แปลน" เราสามารถใส่ทุกอย่างในที่สาธารณะได้เสมอดังนั้นทุกกรณีที่เป็นไปได้ความคิดเกี่ยวกับตัวแปร / วิธีการ / ชั้นเรียน ฯลฯ ... ในความคิดของฉันเป็นเพียงความช่วยเหลือในการพัฒนาการบำรุงรักษาโค้ด ตัวอย่างเช่นหากบุคคลที่ดำเนินการต่อรหัสด้วยเขตข้อมูลสาธารณะเขาสามารถทำอะไรและดังนั้นสิ่งที่ "ไร้เหตุผล" ในส่วนที่เกี่ยวกับวัตถุประสงค์ตรรกะของสาเหตุที่รหัสถูกเขียนขึ้น มันเป็นมุมมองของฉัน
เมื่อฉันใช้คลาสสิกคลาสสิกฟิลด์ส่วนตัว / สาธารณะอ่านได้อย่างเดียวสำหรับ 10 สาขาเอกชนฉันควรเขียน 10 คุณสมบัติสาธารณะ! รหัสสามารถใหญ่ขึ้นเร็วขึ้นจริงๆ ฉันค้นพบตัวตั้งค่าส่วนตัวและตอนนี้ฉันใช้คุณสมบัติสาธารณะกับตัวตั้งค่าส่วนตัวเท่านั้น ตัวตั้งค่าสร้างในพื้นหลังเขตข้อมูลส่วนตัว
นั่นเป็นเหตุผลว่าทำไมรูปแบบการเขียนโปรแกรมคลาสสิคแบบเก่าของฉันคือ:
public class MyClass
{
private int _id;
public int ID { get { return _id; } }
public MyClass(int id)
{
_id = id;
}
}
รูปแบบการเขียนโปรแกรมใหม่ของฉัน:
public class MyClass
{
public int ID { get; private set; }
public MyClass(int id)
{
ID = id;
}
}
ลองคิดดูสิ: คุณมีห้องและประตูที่จะเข้าไปในห้องนี้ หากคุณต้องการตรวจสอบว่าใครเข้ามาและรักษาความปลอดภัยในห้องของคุณคุณควรใช้คุณสมบัติไม่เช่นนั้นจะไม่มีประตูใด ๆ และทุกคนสามารถเข้ามาได้อย่างง่ายดายโดยไม่มีข้อบังคับใด ๆ
class Room {
public string sectionOne;
public string sectionTwo;
}
Room r = new Room();
r.sectionOne = "enter";
ผู้คนเข้ามาในส่วนหนึ่งได้อย่างง่ายดายไม่มีการตรวจสอบใด ๆ
class Room
{
private string sectionOne;
private string sectionTwo;
public string SectionOne
{
get
{
return sectionOne;
}
set
{
sectionOne = Check(value);
}
}
}
Room r = new Room();
r.SectionOne = "enter";
ตอนนี้คุณตรวจสอบบุคคลและรู้ว่าเขามีสิ่งชั่วร้ายกับเขาหรือไม่
ฟิลด์เป็นตัวแปรในคลาส เขตข้อมูลเป็นข้อมูลที่คุณสามารถห่อหุ้มผ่านการใช้งานของการปรับเปลี่ยนการเข้าถึง
คุณสมบัติคล้ายกับฟิลด์ที่กำหนดสถานะและข้อมูลที่เกี่ยวข้องกับวัตถุ
ซึ่งแตกต่างจากสนามคุณสมบัติมีไวยากรณ์พิเศษที่ควบคุมวิธีการที่คนอ่านข้อมูลและเขียนข้อมูลเหล่านี้จะเรียกว่าผู้ประกอบการได้รับและการตั้งค่า ตรรกะการตั้งค่ามักจะสามารถใช้ในการตรวจสอบ
คุณสมบัติเป็นสมาชิกชั้นเรียนชนิดพิเศษในคุณสมบัติเราใช้ชุด Set หรือ Get ที่กำหนดไว้ล่วงหน้าโดยใช้ accessors ซึ่งเราสามารถอ่านเขียนหรือเปลี่ยนค่าของฟิลด์ส่วนตัว
ตัวอย่างเช่นให้เราใช้คลาสที่Employee
มีฟิลด์ส่วนตัวสำหรับชื่ออายุและ Employee_Id เราไม่สามารถเข้าถึงฟิลด์เหล่านี้จากนอกคลาส แต่เราสามารถเข้าถึงฟิลด์ส่วนตัวเหล่านี้ผ่านคุณสมบัติ
ทำไมเราถึงใช้คุณสมบัติ?
ทำให้ฟิลด์คลาสเป็นแบบสาธารณะและเปิดเผยว่ามีความเสี่ยงเนื่องจากคุณจะไม่สามารถควบคุมสิ่งที่ได้รับมอบหมาย & ส่งคืนได้
เพื่อให้เข้าใจอย่างชัดเจนด้วยตัวอย่างให้นักเรียนชั้นเรียนที่มี ID, รหัสผ่าน, ชื่อ ในตัวอย่างนี้มีปัญหากับฟิลด์สาธารณะ
ในการลบปัญหานี้เราใช้วิธีรับและตั้งค่า
// A simple example
public class student
{
public int ID;
public int passmark;
public string name;
}
public class Program
{
public static void Main(string[] args)
{
student s1 = new student();
s1.ID = -101; // here ID can't be -ve
s1.Name = null ; // here Name can't be null
}
}
ตอนนี้เรานำตัวอย่างของวิธี get และ set
public class student
{
private int _ID;
private int _passmark;
private string_name ;
// for id property
public void SetID(int ID)
{
if(ID<=0)
{
throw new exception("student ID should be greater then 0");
}
this._ID = ID;
}
public int getID()
{
return_ID;
}
}
public class programme
{
public static void main()
{
student s1 = new student ();
s1.SetID(101);
}
// Like this we also can use for Name property
public void SetName(string Name)
{
if(string.IsNullOrEmpty(Name))
{
throw new exeception("name can not be null");
}
this._Name = Name;
}
public string GetName()
{
if( string.IsNullOrEmpty(This.Name))
{
return "No Name";
}
else
{
return this._name;
}
}
// Like this we also can use for Passmark property
public int Getpassmark()
{
return this._passmark;
}
}
ข้อมูลเพิ่มเติม: โดยค่าเริ่มต้นการเข้าถึงและการตั้งค่า accessors จะสามารถเข้าถึงได้เหมือนกับทรัพย์สิน คุณสามารถควบคุม / จำกัด การเข้าถึงสำหรับแต่ละคน (เพื่อรับและตั้งค่า) โดยใช้ตัวดัดแปลงการเข้าถึงที่ จำกัด มากขึ้น
ตัวอย่าง:
public string Name
{
get
{
return name;
}
protected set
{
name = value;
}
}
รับที่นี่ยังคงเข้าถึงสาธารณะ (เป็นทรัพย์สินที่เป็นสาธารณะ) แต่การตั้งค่าได้รับการคุ้มครอง
คุณสมบัติที่ใช้ในการเปิดเผยข้อมูล พวกเขาใช้ accessors (set, get) ซึ่งค่าของฟิลด์ส่วนตัวสามารถอ่านเขียนหรือจัดการได้
คุณสมบัติไม่ได้ตั้งชื่อที่เก็บสินค้า แต่พวกเขามี accessors ที่อ่านเขียนหรือคำนวณค่าของพวกเขา
การใช้คุณสมบัติเราสามารถตั้งค่าการตรวจสอบกับประเภทของข้อมูลที่ตั้งค่าในเขตข้อมูล
ตัวอย่างเช่นเรามีอายุฟิลด์จำนวนเต็มส่วนตัวว่าเราควรอนุญาตค่าบวกเนื่องจากอายุไม่สามารถลบได้
เราสามารถทำได้สองวิธีโดยใช้ตัวรับและตัวตั้งค่าและการใช้คุณสมบัติ
Using Getter and Setter
// field
private int _age;
// setter
public void set(int age){
if (age <=0)
throw new Exception();
this._age = age;
}
// getter
public int get (){
return this._age;
}
Now using property we can do the same thing. In the value is a key word
private int _age;
public int Age{
get{
return this._age;
}
set{
if (value <= 0)
throw new Exception()
}
}
คุณสมบัติใช้งานอัตโนมัติหากเราไม่ใช้ตรรกะในการรับและตั้งค่า accessors เราสามารถใช้คุณสมบัติใช้งานอัตโนมัติ
เมื่อคอมไพล์คุณสมบัติที่ดำเนินการโดยอัตโนมัติสร้างฟิลด์ส่วนตัวที่ไม่ระบุชื่อที่สามารถเข้าถึงได้ผ่านการรับและตั้งค่า accessors
public int Age{get;set;}
คุณสมบัติ นามธรรมคลาสนามธรรมอาจมีคุณสมบัตินามธรรมซึ่งควรนำไปใช้ในคลาสที่ได้รับ
public abstract class Person
{
public abstract string Name
{
get;
set;
}
public abstract int Age
{
get;
set;
}
}
// overriden something like this
// Declare a Name property of type string:
public override string Name
{
get
{
return name;
}
set
{
name = value;
}
}
เราสามารถตั้งค่าทรัพย์สินส่วนตัวในที่นี้เราสามารถตั้งค่าคุณสมบัติอัตโนมัติแบบส่วนตัว (ตั้งค่าด้วยในชั้นเรียน)
public int MyProperty
{
get; private set;
}
คุณสามารถบรรลุเดียวกันกับรหัสนี้ ในคุณสมบัติชุดคุณสมบัตินี้ไม่สามารถใช้งานได้เนื่องจากเราต้องตั้งค่าเป็นฟิลด์โดยตรง
private int myProperty;
public int MyProperty
{
get { return myProperty; }
}
กรณีส่วนใหญ่นั้นจะเป็นชื่อคุณสมบัติที่คุณเข้าถึงซึ่งแตกต่างจากชื่อตัวแปร ( ฟิลด์ ) เหตุผลที่ถือว่าเป็นแนวปฏิบัติที่ดีใน. NET และใน C # โดยเฉพาะเพื่อปกป้องข้อมูลทุกชิ้นภายในชั้นเรียน ไม่ว่าจะเป็นตัวแปรอินสแตนซ์หรือตัวแปรสแตติก (ตัวแปรคลาส) เนื่องจากเกี่ยวข้องกับคลาส
ปกป้องตัวแปรเหล่านั้นทั้งหมดด้วยคุณสมบัติที่สอดคล้องกันซึ่งช่วยให้คุณสามารถกำหนดตั้งค่าและรับ อุปกรณ์เสริมและทำสิ่งต่าง ๆ เช่นการตรวจสอบความถูกต้องเมื่อคุณจัดการกับข้อมูลเหล่านั้น
แต่ในกรณีอื่น ๆ เช่นMath class (System namespace) มีคุณสมบัติสแตติกสองสามตัวที่สร้างขึ้นในคลาส หนึ่งในนั้นคือค่าคงที่ทางคณิตศาสตร์ของPI
เช่น. Math.PI
และเนื่องจาก PI เป็นข้อมูลที่กำหนดชัดเจนเราจึงไม่จำเป็นต้องมีหลายสำเนาของ PI จึงเป็นค่าเดียวกันเสมอ ดังนั้นบางครั้งตัวแปรสแตติกจะถูกใช้เพื่อแชร์ข้อมูลระหว่างวัตถุของคลาส แต่ยังใช้สำหรับข้อมูลคงที่โดยทั่วไปซึ่งคุณต้องการเพียงหนึ่งสำเนาของข้อมูล