程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C#銳利體驗(七)(1)

C#銳利體驗(七)(1)

編輯:關於C語言

第七講 域與屬性

域(FIEld)又稱成員變量(Member Variable),它表示存儲位置,是C#中類不可缺少的一部分。域的類型可以是C#中任何數據類型。但對於除去string類型的其他引用類型由於在初始化時涉及到一些類的構造器的操作,我們這裡將不提及,我們把這一部分內容作為“類的嵌套”放在“接口 繼承與多態”一講內來闡述。

域分為實例域和靜態域。實例域屬於具體的對象,為特定的對象所專有。靜態域屬於類,為所有對象所共用。C#嚴格規定實例域只能通過對象來獲取,靜態域只能通過類來獲取。例如我們有一個類型為MyClass的對象MyObject,MyClass內的實例域instanceField(存取限制為public)只能這樣獲取:MyObject. instanceField。而MyClass的靜態域staticField(存取限制為public)只能這樣獲取:MyClass.staticField。注意靜態域不能像傳統C++那樣通過對象獲取,也就是說MyObject.staticFIEld的用法是錯誤的,不能通過編譯器編譯。

域的存取限制集中體現了面向對象編程的封裝原則。如前所述,C#中的存取限制修飾符有5種,這5種對域都適用。C#只是用internal擴展了C++原來的frIEnd修飾符。在有必要使兩個類的某些域互相可見時,我們將這些類的域聲明為internal,然後將它們放在一個組合體內編譯即可。如果需要對它們的繼承子類也可見的話,聲明為protected internal即可。實際上這也是組合體的本來意思--將邏輯相關的類組合封裝在一起。

C#引入了readonly修飾符來表示只讀域,const來表示不變常量。顧名思義對只讀域不能進行寫操作,不變常量不能被修改,這兩者到底有什麼區別呢?只讀域只能在初始化--聲明初始化或構造器初始化--的過程中賦值,其他地方不能進行對只讀域的賦值操作,否則編譯器會報錯。只讀域可以是實例域也可以是靜態域。只讀域的類型可以是C#語言的任何類型。但const修飾的常量必須在聲明的同時賦值,而且要求編譯器能夠在編譯時期計算出這個確定的值。const修飾的常量為靜態變量,不能夠為對象所獲取。const修飾的值的類型也有限制,它只能為下列類型之一(或能夠轉換為下列類型的):sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string, enum類型, 或引用類型。值得注意的是這裡的引用類型,由於除去string類型外,所有的類型出去null值以外在編譯時期都不能由編譯器計算出他們的確切的值,所以我們能夠聲明為const的引用類型只能為string或值為null的其他引用類型。顯然當我們聲明一個null的常量時,我們已經失去了聲明的意義--這也可以說是C#設計的尴尬之處!

這就是說,當我們需要一個const的常量時,但它的類型又限制了它不能在編譯時期被計算出確定的值來,我們可采取將之聲明為static readonly來解決。但兩者之間還是有一點細微的差別的。看下面的兩個不同的文件:

//file1.cs
//csc /t:library file1.cs
using System;
namespace MyNamespace1
{
public class MyClass1
{
        public static readonly int myFIEld = 10;
    }
}
//file2.cs
//csc /r:file1.dll file2.cs
using System;
namespace MyNamespace2
{
public class MyClass1
{
        public static void Main()
        {
Console.WriteLine(MyNamespace1.MyClass1.myFIEld);
        }
    }
}

我們的兩個類分屬於兩個文件file1.cs 和file2.cs,並分開編譯。在文件file1.cs內的域myField聲明為static readonly時,如果我們由於某種需要改變了myField的值為20,我們只需重新編譯文件file1.cs為file1.dll,在執行file2.exe時我們會得到20。但如果我們將static readonly改變為const後,再改變myField的初始化值時,我們必須重新編譯所有引用到file1.dll的文件,否則我們引用的MyNamespace1.MyClass1.myFIEld將不會如我們所願而改變。這在大的系統開發過程中尤其需要注意。實際上,如果我們能夠理解const修飾的常量是在編譯時便被計算出確定的值,並代換到引用該常量的每一個地方,而readonly時在運行時才確定的量--只是在初始化後我們不希望它的值再改變,我們便能理解C#設計者們的良苦用心,我們才能徹底把握const和readonly的行為!

域的初始化是面向對象編程中一個需要特別注意的問題。C#編譯器缺省將每一個域初始化為它的默認值。簡單的說,數值類型(枚舉類型)的默認值為0或0.0。字符類型的默認值為'\x0000'。布爾類型的默認值為false。引用類型的默認值為null。結構類型的默認值為其內的所有類型都取其相應的默認值。雖然C#編譯器為每個類型都設置了默認類型,但作為面向對象的設計原則,我們還是需要對變量進行正確的初始化。實際上這也是C#推薦的做法,沒有對域進行初始化會導致編譯器發出警告信息。C#中對域進行初始化有兩個地方--聲明的同時進行初始化和在構造器內進行初始化。如前所述,域的聲明初始化實際上被編譯器作為賦值語句放在了構造器的內部的最開始處執行。實例變量初始化會被放在實例構造器內,靜態變量初始化會被放在靜態構造器內。如果我們聲明了一個靜態的變量並同時對之進行了初始化,那麼編譯器將為我們構造出一個靜態構造器來把這個初始化語句變成賦值語句放在裡面。而作為const修飾的常量域,從嚴格意義上講不能算作初始化語句,我們可以將它看作類似於C++中的宏代換。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved