域和屬性
域表示與對你或類相關聯的變量,聲明格式如下:
attributes field-modifiers type variable-declarators;
域的修飾符field-modifiers可以是:
new
public
protected
internal
private
static
readonly
實際上,域相當於c++中的類的簡單成員變量,在下面的代碼中,類a包含了三個域:公有的x和
y,以及私有的z.
class a
{
public int x;
public string y;
private float z;
}
靜態域和非靜態域
靜態域的聲明是使用static修飾符,其它的域都是非靜態域,靜態域和非靜態域分別屬於C#
中靜態變量和非靜態變量.
若將一個域說明為靜態的,無論建立多少個該類的實例,內存中只存在一個靜態數據的拷貝.
當這個類的第一個實例建立時,域被初始化.以後再進行類的實例化時,不再對其進行初始化
,所有屬於這個類的實例共享一個副本.
與之相反,非靜態域在類的每次實例化時,每個實例都擁有一份單獨的拷貝.
下面的例子清楚的反映了二者之間的區別.
using System;
public class Count
{
static int count;
int number;
public Count()
{
count = count + 1;
number = count;
}
public void show()
{
Console.WriteLine("object{0}:Number={1},Count={2}",number, number,
count);
}
}
class test
{
public static void Main()
{
Count a = new Count();
a.show();
Console.WriteLine();
Count b = new Count();
a.show();
b.show();
Console.WriteLine();
Count c = new Count();
a.show();
b.show();
c.show();
}
}
程序運行結果:
object1:Number=1,Count=1
object1:Number=1,Count=2
object2:Number=2,Count=2
object1:Number=1,Count=3
object2:Number=2,Count=3
object3:Number=3,Count=3
上例的例子中,類Count中域count被聲明為靜態,為所有類的實例所共享.類每進行一次實例
化,它的值就加1,這個操作就在構造函數中實現,因為可以用於對系統中類的實例數進行計
數.
域number用來存放當前實例的編號.當被實例化時,在構造函數中就對編號進行賦值,從而可
以看出實例化的順序.
方法show()用來在屏幕上打印出當前類的實例數,還有類的各個實例的編號.
從上面的例子中可以看,出無論何時,類的所有實例的count值都是相同的,說明它們共享一
個數據,count域只有一個副本.而每個實例的標號都是不同的,一旦實例化,標號就不再變化
了.
只讀域
域的聲明中如果加上了readonly修飾符,表明該域為只讀域.對於只讀域我們只能在域的定
議中和它所屬類的構造函數中進行修改,在其它情況下,域是"只讀"的.
public class A
{
public static readonly double PI=3.14159;
public static readonly Color White=new Color(255,255,255);
public static readonly int kByte=1024;
}
這樣,在程序中我們就可以直接使用PI來指代圓周率,white來表示白色...
那麼使用static readonly與使用const有什麼區別?簡單地說,const型表達式的值在編譯時
形成而static readonly表達式的值直到程序運行時才形成.看下面這個列子.
using System;
namespace Program1
{
public class A
{
public static readonly int x=1;
}
}
namespace Program2
{
class Test
{
static void Main()
{
Console.WriteLine(Program1.A.x);
}
}
}
假定名字空間Program1&Program2表示兩個分別獨立編譯的程序.在這里域x為靜態只讀的,
它的值由在編譯時形成的,所以無認是否改變Program1中x的值,只要不重新編譯
Program2,Program2的輸出就不會發生變化.如果Program2已經安裝在用戶的系統上,對
Program1的升級不會影到舊的Program2的使用.這种技術有利於進行版本控制.
域的初始化
對靜態變量,非靜態的對像變量和數組元素,這些變自動初始化為體身的默認值.對於所有引用類型的變量,默認值為null.所有值類型的變量見下表:
對於struct類型的變量,默認的初始化將對構成該結構的每一個值類型初始化為上表中的默
認值,對構成其的每一個引用類型初始化為null.
如果在類中,沒有顯式地對域進行初始化,系統將賦予其一個默認值.域的默認初始化分為兩
种情況:對於靜態域,類在裝載時對其進行初始化;對於非靜態域,在類的實例創建時進行初
始化.在默認的初始化之前,域的值是不可預測的.
以下的代碼是合法的:
class Test
{
static int a=b+1;
static int b=a+1;
}
實際上等價於:a=1,b=2
而下面的代碼則是非法的:
class A
{
int x=1;
int y=x+1;
}
因為非靜太變量x在類A實例化以前並沒有初始化,代碼y=x+1無法得到的x的值.
屬性
屬性是對現實世界中實體特征的抽像,它提供了對類或是對像性的訪問.類的屬性所描述的
是狀態信息,在類的某個實例中屬性的值表示該對像的狀態值.
C#中的屬性更充分地體現了對像的的封裝性;不直接操作類的數據內容,而是通過訪問器進
行訪問.它借助於get和set對屬性的值進行讀寫,這在C++中是需要程序員手工完成的一項工
作.
屬性采用如下方式進行聲明:
attributes property-modifiers type member-name {accessor-declarations}
屬性的修飾符property-modifiers有:
new
public
protected
internal
private
static
virtual
sealed
override
abstract
以上修飾符中,static,virtual,override和abstract修飾符不能同時使用.
訪問屬性的值
在屬性的訪問聲明中,對屬性的值的讀操作用get關鍵字標出,對屬性的值的寫操作用set關
鍵字標出.下面是一個例子
using System;
public class File
{
private string s_filename;
public string Filename
{
get{return s_filename;}
set
{
if(s_filename!=value)
{
s_filename=value;
}
}
}
}
public class Test
{
public static void Main()
{
File f=new File();
f.Filename="myfile.txt";
string s=f.Filename;
Console.WriteLine("Filename:{0}",s);
}
}
程序運行結果:
Filename:myfile.txt
在屬性的訪問聲明中:
只有set訪問器,表明屬性的值只能進行設置而不能讀出.
只有get訪問器,表明屬性的值是只讀的,不能改寫.
同時有set訪問器和get訪問器,表明屬性的值的讀寫都是允許的.
除了使用abstract修飾符的抽像屬性,每個訪問器的執行體只有分號";",其它所有屬性的get訪問器都通過return來讀取屬性的值,set訪問器都通過value來設置屬性的值.
舉個例子,旅館對信宿人員進行登記,要記錄的信息有:客人姓名,性別,所住的房間號,已住宿天數.這里,客人的姓名和性別一經確定就不能再更改了,用戶可以要求改變房間,住宿的天數當然也是不斷變化的.我們在類的構造函數中對客人的姓名和性別進行初始化,在四個屬性中,客人的姓名和性別是只讀的,故只有get訪問器;房間號和住宿天數允許改變,同時有set訪問器和get訪問器.
using System;
public class Customer
{
public enum sex
{
man,
woman,
};
private string s_name;
Public string Name
{
get{return s_name;}
}
private sex m_sex;
public sex Sex
{
get{return m_sex;}
}
private string s_no;
public string No
{
get{return s_no;}
set
{
if(s_no!=value)
{
s_no=value;
}
}
}
private int i_day;
public int Day
{
get{return i_day;}
set
{
if(i_day!=value)
{
i_day=value;
}
}
}
public void Customer(string name,sex sex,string no,int day)
{
s_name=name;
m_sex=sex;
s_no=no;
i_day=day;
}
}