C#欄位為什麼用屬性封裝?
我們知道,類成員包括變數和方法。如果希望其他類能夠訪問成員變數的值,就必須定義成公有的,而將變數設為公有public,那這個成員變數的就可以被任意訪問(包括修改,讀取),這樣不利於資料安全。那怎麼辦呢?
C#通過屬性特性讀取和寫入欄位(成員變數),而不直接直接讀取和寫入,以此來提供對類中欄位的保護。屬性可用於類內部封裝欄位。屬性是C#面向物件技術中封裝性的體現。
注意:欄位就是類的成員變數,為配合屬性而這樣稱呼的。
屬性和欄位的區別:屬性是邏輯欄位;屬性是欄位的擴充套件,源於欄位;屬性並不佔用實際的記憶體,欄位佔記憶體位置及空間。屬性可以被其它類訪問,而大部分欄位不能直接訪問。屬性可以對接收的資料範圍作限定,而欄位不能。(也就是增加了資料的安全性)最直接的說:屬性是被
class Card
{
public string Name;
}
而非要做一個private欄位+public屬性?
class Card
{
private string name;
public string Name
{
get { return this.name;}
set { this.name=value;}
}
}
下面我們用程式碼一步一步來說明為什麼要使用屬性。
using System;
//打個比方我們有個網站,每當有新使用者註冊的時候,我們需要記錄這些使用者的資訊
//宣告一個User類來記錄這些使用者的資訊
class User
{
//姓名,性別
public string name;
public string sex;
}
//宣告一個類去使用User類
class Property
{
static void Main()
{
//例項化一個張三User物件
User zs = new User();
//對其賦值
zs.name = "張三";
zs.sex = "男";
Console.WriteLine("姓名:" + zs.name + "性別:" +zs.sex);
}
}
通過編譯執行,這段程式碼正常執行,這個程式乍看一下感覺沒有什麼問題。但是仔細分析,就會發現:
所有欄位都是公有的,不利於欄位的保護,只要例項化了這個類,都可以修改其中的值。如果性別輸入了男女之外的字元,系統是不會識別的。
比如把zs.sex = "男";改成zs.sex = "牛";。執行程式碼結果肯定張三的性別成牛了...這個時候就不合邏輯了。
現在大家可以明顯的感覺到User類的封裝非常不合理,存在著非常大的缺陷,那麼該如何修改呢?這個時候大家馬上會想到是不是可以專門宣告一個方法給性別賦值呢,好!我們就來實現這個方法。
using System;
class User
{
public string name;
public string sex;
//SetSex方法
public void SetSex(string values)
{
if (values == "男" || values =="女")
{
sex =values;
}
else
{
Console.WriteLine("性別只能為“男”或“女”");
}
}
}
class Property
{
static void Main()
{
User zs = new User();
zs.name = "張三";
//直接呼叫SetSex賦值
zs.SetSex("牛");
Console.WriteLine("姓名:" + zs.name + "性別:" +zs.sex);
}
}
SetSex這個方法乍一看還可以,但是不要忘記name和sex欄位還是public屬性,我們依然可以直接去呼叫它,或者說去修改它,一樣可以把sex設為“牛”。給類的欄位設定為public意味著破壞了類的封裝,這樣呢會存在潛在的危險。所以呢要設為private,這個時候就分別宣告方法去讀取和設定這2個欄位,修改如下:
using System;
class User
{
//設為私有的
private string name;
private string sex;
//設定
public void SetName(string values)
{
name = values;
}
//讀取
public string GetName()
{
return name;
}
public void SetSex(string values)
{
if (values == "男" || values =="女")
{
sex =values;
}
else
{
Console.WriteLine("性別只能為“男”或“女”");
}
}
public string GetSex()
{
return sex;
}
}
class Property
{
static void Main()
{
User zs = new User();
zs.SetName("張三");
zs.SetSex("牛");
Console.WriteLine("姓名:" + zs.GetName() +"性別:" +zs.GetSex());
}
}
大家執行編譯下看下效果是沒有問題的。現在這個類的設計就比較合理了,我們看name和sex它們是private欄位,也就是說在類的外部是不能訪問的,這樣呢就保證了它的安全性。當用戶想給性別欄位新增非法欄位的時候,SetSex方法內會對這個新增的值進行判斷,如果不為男或女,值就不會被新增。通過方法雖然解決了上面的問題,但是每建立一個物件,輸入欄位值時就必須呼叫上面方法。如果不知道,就無法呼叫。關鍵是不夠簡便。為了提高資料安全性,並且有效解決上面的問題,C#推出了屬性。可以建立屬性,將欄位和屬性封裝在一起。通過屬性可以像訪問欄位一樣訪問資料成員,實現資料的封裝,避免使用非法資料賦值,保證資料完整性,同時類內部發生修改時,避免整個程式的修改。
C#屬性的應用
1、打個比方我們有個網站,每當有新使用者註冊的時候,我們需要記錄這些使用者的資訊。建立一個User類來記錄使用者的註冊資訊,包括用成員變數(欄位)使用者名稱,密碼,性別。
2、用屬性封裝3個欄位,實現賦值規則使用者名稱只能以字母開頭,密碼長度不小於6(預設6個1),性別只能是“男”或“女”。
3、為User類新增公共的DisplayInfo方法。
4、在主方法中讓使用者註冊資訊,用User物件記錄,然後呼叫物件的DisplayInfo方法顯示註冊資訊。
程式碼如下:
User類:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
namespaceWebsite
{
class User
{
stringname;
stringpassword;
string sex;
public string Name
{
get{ return name; }
set
{
if(char.IsLetter(value,0))
{
name = value;
}
else
{
Console.WriteLine("使用者名稱非法,必須以字母開頭");
Console.WriteLine("使用者名稱預設為:abc");
name = "abc";
}
}
}
public string Password
{
get{ return password; }
set
{
if(value.Length >= 6)
{
password = value;
}
else
{
Console.WriteLine("密碼非法,密碼長度不小於6");
Console.WriteLine("密碼預設為:111111");
password = "111111";
}
}
}
public string Sex
{
get{ return sex; }
set
{
if (value.Equals("男") || value.Equals("女"))
{
sex = value;
}
else
{
Console.WriteLine("性別非法,必須為“男”或“女”");
Console.WriteLine("性別預設為:男");
sex = "男";
}
}
}
public void DisplayInfo()
{
Console.WriteLine("使用者名稱:{0}", this.Name);
Console.WriteLine("密碼:0}", this.Password);
Console.WriteLine("性別:{0}", this.Sex);
}
}
}
主類:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
namespaceWebsite
{
class Program
{
static void Main(string[] args)
{
Useru = new User();
Console.WriteLine("===============使用者註冊===============");
Console.Write("請輸入使用者名稱:");
u.Name = Console.ReadLine();
Console.Write("請輸入密碼:");
u.Password = Console.ReadLine();
Console.Write("請輸入性別");
u.Sex = Console.ReadLine();
Console.WriteLine("===============使用者資訊===============");
u.DisplayInfo();
}
}
}