1.常量
常量是一個特殊的符號,它有一個不改變的值,定義常量時,它的值必須在編譯時確定,確定後編譯器將常量的值保存到程序集的元數據中。常量總是被視為靜態成員,而不是實例成員,定義常量將導致創建元數據。
這意味著只能為編譯器確定的基元類型定義常量。然後C#也允許定義一個非基元類型的常量變量,前提是把它的值設為null。
class Program
{
public static const Program p=null;
public static const Program p=new Program();//編譯出錯,只能用null對引用類型(字符串除外)的常量字段進行初始化
}
代碼引用一個常量符號時,編譯器會在定義常量的程序集的元數據中查找該符號,然後提取常量的值並將值嵌入生成的IL代碼中,由於常量的值直接嵌入代碼,所以運行時不會為常量分配任何內存,因此,不能獲取常量的地址,也不能以傳址的方式傳遞常量。
所以說常量沒有很好的跨程序集版本控制特性,只有在確定一個符號的值從不變化時,才使用常量。
如果希望在運行時從一個程序集中提取另一個程序集中的值,那麼不應該使用常量,而應該使用readonly字段。
2.字段
字段是一種數據成員,容納了一個值類型的實例,或者對一個引用類型的引用。
CLR支持類型字段和實例字段,對於類型字段,用於容納字段數據的動態內存是在類型對象中分配的。而類型對象是在類型加載到一個AppDomain時創建的,什麼時候加載到AppDomain呢?這通常是在引用了該類型的任何方法首次進行JIT編譯時。對於實例字段,用於容納字段數據的動態內存則是在構造類型的一個實例時分配的。
CLR支持readonly字段和read/write字段,大多數字段都是read/write的,代碼執行中字段的值可以多次改變,但是readonly字段只能在一個構造器方法中寫入。
internal class Manager
{
public readonly int d=200;
public Manager(int r)
{
//修改字讀字段d,因為代碼在構造器中,所以允許這樣做。
this.d = r;
}
}
class Program
{
public const Program p=null;
static void Main()
{
Manager m = new Manager(400);
Console.WriteLine(m.d);//
}
當某個字段時引用類型時,並且該字段標記為readonly,那麼不可改變的是引用,而不是字段引用的對象:
internal class Manager
{
public static readonly int[] n =new int[]{22,33,44,55,66};
public readonly int d=200;
public Manager(int r)
{
this.d = r;
}
}
class Program
{
public const Program p=null;
static void Main()
{
Manager.n[0] = 400;
Manager.n[1] = 800;
foreach (int p in Manager.n)
{
Console.WriteLine(p);
}//輸出400,800,44,55,66
}
}
許多字段都是內聯初始化的(直接在代碼中賦值來初始化,而不是通過構造器。)C#允許使用這種方便的內聯初始化語法來初始化類的常量,字段。但是C#實際是在構造器中對字段進行初始化的,字段的內聯初始化只不過是語法上的簡化而已。在C#中初始化一個字段時,如果使用內聯語法,而不是在構造器中賦值,有一些性能問題需要考慮
作者 小小白白