C#中的屬性(get、set、value)
C#語言在面向物件設計和程式設計中對資料安全提出了嚴格的要求,其中一個重要的原則就是資料封裝。根據這一原則,C#程式設計中要求開發人員對特定類的資料欄位儘量不以公有方式提供給外界。因此在類內部多數字段的訪問許可權被限定為private或是public,而這些欄位與外界的交流經常採用屬性來進行。
屬性使類能夠以一種公開的方法獲取和設定值,同時隱藏實現或驗證程式碼。
屬性是這樣的成員:它們提供靈活的機制來讀取、編寫或計算私有欄位的值。
可以像使用公共資料成員一樣使用屬性,但實際上它們是稱作“訪問器”的特殊方法。這 使得可以輕鬆訪問資料,此外還有助於提高方法的安全性和靈活性。
屬性使類能夠以一種公開的方法獲取和設定值,同時隱藏實現或驗證程式碼。
get 屬性訪問器用於返回屬性值,而 set 訪問器用於分配新值。 這些訪問器可以有不同的訪問級別。
get 訪問器體與方法體相似。 它必須返回屬性型別的值。執行 get 訪問器相當於讀取欄位的值
get 訪問器必須以 return 或 throw 語句終止,並且控制權不能離開訪問器體。
value 關鍵字用於定義由 set 取值函式分配的值。
不實現 set 取值函式的屬性是隻讀的。
不實現 set 取值函式的屬性是隻讀的。
屬性的定義通常由以下兩部分組成:
1需要封裝的專用資料成員
private int _nValue = 1;
private double _dValue = 10.101 ;
private char _chValue = 'a';
2向外界提供訪問的公共屬性:
//讀寫屬性nValue:
public int nValue
{
get
{
return _nValue;
}
set
{
_nValue = value;
}
}
//只讀屬性dValue:
public double dValue
{
get
{
return _dValue;
}
}
//只寫屬性chValue:
public char chValue
{
set
{
_chValue = value ;
}
}
當屬性的訪問器中不需要其他邏輯時,自動實現的屬性可使屬性宣告更加簡潔。客戶端還可以通過這些屬性建立物件,例如下面的程式碼,編譯器將建立一個私有的匿名支援欄位,該欄位只能通過屬性的get和set訪問器進行訪問。
class Customer
{ // Auto-Impl Properties for trivial get and set
public double TotalPurchases { get; set; }
public string Name { get; set; }
public int CustomerID { get; set; }
// Constructor
public Customer(double purchases, string name, int ID)
{
TotalPurchases = purchases;
Name = name;
CustomerID = ID;
}
// Methods
public string GetContactInfo() {return "ContactInfo";}
public string GetTransactionHistory() {return "History";}
// .. Additional methods, events, etc.
}
class Program
{
static void Main()
{
// Intialize a new object.
Customer cust1 = new Customer ( 4987.63, "Northwind",90108 );
//Modify a property
cust1.TotalPurchases += 499.99;
}
}
下面講一個如何使用自動實現的屬性實現輕量類:
此示例演示如何建立一個不可變輕量類,用於僅封裝一組自動實現的屬性。當您必須使用引用型別語義時,請使用此種構造而不是結構。
請注意:對於自動實現的屬性,需要 get 和 set 訪問器。 要使該類不可變,請將 set 訪問器宣告為 private。 但是,宣告私有 set 訪問器時,不能使用物件初始值來初始化屬性。
下面的示例演示兩種方法來實現具有自動實現屬性的不可變類。第一個類使用建構函式初始化屬性,第二個類使用靜態工廠方法。
class Contact
{
// Read-only properties.
public string Name { get; private set; }
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 set; }
// 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.
*/
上訴中,通過get存取器和set存取器將封裝好的專有資料成員和共同屬性關聯起來。
此時,value關鍵字是時候出場了。
在普通的C#程式中,一般不能通過常用的除錯手段獲得value值傳遞的詳細過程,不能像C++中一樣跟蹤指標的變化情況。當使用如下語句給屬性賦值:
Class ValueCollector{...};
ValueCollector newValue = new ValueCollector();
newValue.nValue = 10;
新物件newValue的私有資料成員_nValue通過屬性nValue的set方法由原來的1改變為10;
賦值語句的右值通過隱式引數value進入屬性set方法內,成功改變整型私有變數的值。
在這一過程中,value引數的型別是整型,與屬性的型別是一致的。當屬性的型別改變為char,value引數的屬性也相應的改變為字元型。
這種引數型別的自動轉換時基於.NETFramework提供的型別轉換器而實現的,CLR將C#原始碼編譯成中間語言IL,在這種類彙編的高階機器語言中可以發現value引數的傳遞機制。