在《重構》之Split Temporary Variables中,要使用到final這個類型。
由於例子是用java寫的,於是我想找到c#中對應final的修飾符。
結果找到了兩個:const和readonly
下面看看這兩個有什麼區別:
· readonly和const都是用來標識常量的[1]。
· const可用於修飾class的field或者一個局部變數(local variable);而readonly僅僅用於修飾class的field。
· const常量的值必定在編譯時間就已明確並且恒定的;而readonly常量卻有一點不同,那就是其值可以在運行時編譯,當然,它也必須遵守作為常量的約束,那就是值必須恒定不變。
· const常量必須在聲明的同時對其進行賦值,並且確保該值在編譯時間可確定並恒定;而readonly常量則可以根據情況選擇在聲明的同時對其賦予一個編譯時間確定並恒定的值,或者將其值的初始化工作交給執行個體建構函式(instant constructor)完成。如:public readonly string m_Now = DateTime.Now.ToString();,m_Now會隨著運行時實際情況變化而變化。
· const常量屬於類層級(class level)而不是執行個體對象層級(instant object level),並且它不能跟static結合一起使用,該常量的值將由整個類的所有執行個體對象共同分享(詳細論述參見後面的Remark地區)。
· readonly常量既可以是類層級也可以是執行個體對象層級的,這取決於它的聲明以及初始化工作怎麼實施。readonly可以與static結合使用,用於指定該常量屬於類層級,並且把初始化工作交由靜態建構函式(static constructor)完成(有關如何把readonly常量聲明為類層級或執行個體對象層級的論述清參見後面的Remark地區) 。
· 能被const修飾聲明為常量的類型必須是以下的基元類型(primitive type):sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, float, bool, decimal, string。
· object, 數組(Array)和結構(struct)不能被聲明為const常量。
· 一般情況下,參考型別是不能被聲明為const常量的,不過有一個例外:string。該參考型別const常量的值可以有兩種情況,string或null。其實,string雖然是參考型別,但是.NET卻對它特別處理,這種處理叫做字串恒定性(immutable),使得string的值具有唯讀特性。有關字串恒定性的內容,可以參考《Microsoft .NET架構程式設計(修訂版)》。
從以上關於兩者區別的描述可以看出,常量有三種情況:類層級的,執行個體層級的,局部變數(local variable)。 前兩者的區別和實現已經很明顯,局部變數(local variable)這個東東我還沒見過,下面看一下到底是什麼:
看了一下才知道,原來我們在方法中使用的變數就叫做局部變數。比如:
public static void Main()
{
int j=30;
Console.WriteLine(j);//輸出結果:30
}
中,裡面的j就是局部變數。
因此,可以總結如下:
局部變數:
public static void Main()
{
int j=30;
Console.WriteLine(j);//輸出結果:30
}
局部變數標識為常量:
public static void Main()
{
const int j=30;
Console.WriteLine(j);//輸出結果:30
}
執行個體層級的欄位:
public class Test
{
public int j=20;
public static void Main()
{
Console.WriteLine(new Test().j);//輸出結果:20
}
}
執行個體層級的欄位標識為常量:
public class Test
{
Public const int j=20;
public static void Main()
{
Console.WriteLine(new Test().j);//輸出結果:20
}
}
或者:
public class Test
{
Public readonly int j=20;
public static void Main()
{
Console.WriteLine(new Test().j);//輸出結果:20
}
}
或者:
public class Test
{
Public readonly int j;
public Test()
{
j=20; //注意,readonly域只能通過初始化器或類的建構函式設定
}
public static void Main()
{
Console.WriteLine(new Test().j);//輸出結果:20
}
}
類層級的欄位:
public class Test
{
Public static int j=20;
public static void Main()
{
Console.WriteLine(Test.j);//輸出結果:20
}
}
類層級的欄位標識為常量:
public class Test
{
Public static readonly int j=20;
public static void Main()
{
Console.WriteLine(Test.j);//輸出結果:20
}
}