C#中的靜態常量(const)和動態常量(static和readonly)用法和區別


C#中有兩種常量類型,分別為readonly(運行時常量)與const(編譯時常量),本文將就這兩種類型的不同特性進行比較並說明各自的適用場景。
工作原理
readonly為運行時常量,程序運行時進行賦值,賦值完成后便無法更改,因此也有人稱其為只讀變量。
const為編譯時常量,程序編譯時將對常量值進行解析,並將所有常量引用替換為相應值。
下面聲明兩個常量:

public static readonly int A = 2; //A為運行時常量
public const int B = 3; //B為編譯時常量

下面的表達式:

int C = A + B;

 


經過編譯后與下面的形式等價:

int C = A + 3;

 


可以看到,其中的const常量B被替換成字面量3,而readonly常量A則保持引用方式。
聲明及初始化
readonly常量只能聲明為類字段,支持實例類型或靜態類型,可以在聲明的同時初始化或者在構造函數中進行初始化,初始化完成后便無法更改。
const常量除了可以聲明為類字段之外,還可以聲明為方法中的局部常量,默認為靜態類型(無需用static修飾,否則將導致編譯錯誤),但必須在聲明的同時完成初始化。

數據類型支持
由於const常量在編譯時將被替換為字面量,使得其取值類型受到了一定限制。const常量只能被賦予數字(整數、浮點數)、字符串以及枚舉類型。下面的代碼無法通過編譯:

public const DateTime D = DateTime.MinValue;

改成readonly就可以正常編譯:

1 public readonly DateTime D = DateTime.MinValue;

可維護性
readonly以引用方式進行工作,某個常量更新后,所有引用該常量的地方均能得到更新后的值。
const的情況要稍稍復雜些,特別是跨程序集調用:

 1 public class Class1
 2 {
 3     public static readonly int A = 2; //A為運行時常量
 4     public const int B = 3; //B為編譯時常量
 5 }
 6 
 7 public class Class2
 8 {
 9     public static int C = Class1.A + Class1.B; //變量C的值為A、B之和 
10 }
11 
12 Console.WriteLine(Class2.C); //輸出"5"

 

假設Class1與Class2位於兩個不同的程序集,現在更改Class1中的常量值:

1 public class Class1
2 {
3        public static readonly int A = 4; //A為運行時常量
4        public const int B = 5; //B為編譯時常量
5 }

編譯Class1並部署(注意:這時並沒有重新編譯Class2),再次查看變量C的值:

1 Console.WriteLine(Class2.C); //輸出"7"

結果可能有點出乎意料,讓我們來仔細觀察變量C的賦值表達式:

public static int C = Class1.A + Class1.B;

編譯后與下面的形式等價:

public static int C = Class1.A + 3;

因此不管常量B的值如何變,對最終結果都不會產生影響。雖說重新編譯Class2即可解決這個問題,但至少讓我們看到了const可能帶來的維護問題。

性能比較
const直接以字面量形式參與運算,性能要略高於readonly,但對於一般應用而言,這種性能上的差別可以說是微乎其微。

適用場景
在下面兩種情況下:
a.取值永久不變(比如圓周率、一天包含的小時數、地球的半徑等)
b.對程序性能要求非常苛刻
可以使用const常量,除此之外的其他情況都應該優先采用readonly常量。

 

C#中的static 和Java中的static

簡單,兩者用法完全是一致的。從兩方面討論:

1. 變量是屬於類的,不是實例級別的。只能通過類名調用,不能通過實例調用。

2. 如果在定義時就賦值了,那么在類初始化的時候,最先完成所有靜態變量的賦值。但是要注意,所有靜態變量的初始化順序是無法確定的。

 

C# 中的const 和Java中的finnal

很長一段時間我一直認為兩者是相同的作用,無非是變量初始化后不能更改,即只能在定義時或者構造函數中賦值。然而這僅僅只是片面的,下面將為大家詳細分析:

1.修飾變量

准確的說C#中的const 等價於 Java中的static final,也就是說,Java中final不具有static的功能。而C#中的const具有static的功能。因此在C#中 public static const string 等將於 public const string。

2.修飾類和方法

此時Java中的final類似C#中的sealed,就是說,final修飾的類不能被繼承,final修飾的方法不能被覆蓋。

而C#中的const不能修飾類和方法。

問題:

1. 私有靜態成員的作用(private static 變量)

字面表示私有的,類外不能使用;靜態的,全局變量。看上去很矛盾,又不能被類外使用,要全局的有什么用。問得好,類中全局也是很有意義的,例如 private static int a = 5,那么就可以保證變量a在類的初始化過程中將被優先初始化(在構造函數執行之前)。這樣如果對象A的初始化需要對象B的實例,那么就可以用這種申明,以保證在類A在構造函數中能夠使用類B的實例。同時private又能夠保證類B的實例只能在類A中使用,起到很好的密封作用。

2. 私有最終成員作用(private final 變量)

在類構造函數完成前必須對該成員完成初始化,一旦定義不許更改;該成員只能在本類中使用。實例,子類中都不能使用。

private static final修飾的成員在申明的時就被賦值,保證在構造函數中可以被使用,一個被private static final修飾的成員通常表示其他組件的一個實例,且變量是類中的全局變量。

private final         修飾的成員在構造中被賦值,表示它是該類全局的私有成員變量,且該類的構造需要傳入他們的初始值,才能完成類的初始化。


 

C# const和static readonly區別

const: 用const修飾符聲明的成員叫常量,是在編譯期初始化並嵌入到客戶端程序 
static readonly: 用static readonly修飾符聲明的成員依然是變量,只不過具有和常量類似的使用方法:通過類進行訪問、初始化后不可以修改。但與常量不同的是這種變量是在運行期初始化。

C# const和static readonly區別示例:

 1 using System;  
 2 using System.Collections.Generic;  
 3 using System.Text;  
 4    
 5 namespace Example02Lib  
 6 {  
 7      public class Class1  
 8      {  
 9             public const String strConst = "Const";  
10             public static readonly String strStaticReadonly = "StaticReadonly";  
11             //public const String strConst = "Const Changed";  
12             //public static readonly String strStaticReadonly = "StaticReadonly Changed";  
13      }  
14 } 

客戶端代碼:

 1 using System;  
 2 using System.Collections.Generic;  
 3 using System.Text;  
 4 using Example02Lib;   
 5 namespace Example02  
 6 {  
 7      class Program  
 8      {  
 9            static void Main(string[] args)  
10            {  
11                   //修改Example02中Class1的strConst初始值后,只編譯Example02Lib項目  
12                   //然后到資源管理器里把新編譯的Example02Lib.dll拷貝Example02.exe所在的目錄, 執行Example02.exe  
13                  //切不可在IDE里直接調試運行因為這會重新編譯整個解決方案!!   
14                   //可以看到strConst的輸出沒有改變,而strStaticReadonly的輸出已經改變  
15                  //表明Const變量是在編譯期初始化並嵌入到客戶端程序,而StaticReadonly是在運行時初始化的  
16                 Console.WriteLine("strConst : {0}", Class1.strConst);  
17                 Console.WriteLine("strStaticReadonly : {0}", 
18                 Class1.strStaticReadonly);   
19                 Console.ReadLine();  
20           }  
21      }  
22 } 

修改后的示例:

 1 using System;  
 2 using System.Collections.Generic;  
 3 using System.Text;  
 4    
 5 namespace Example02Lib  
 6 {  
 7        public class Class1  
 8        {  
 9              //public const String strConst = "Const";  
10              //public static readonly String strStaticReadonly = "StaticReadonly";  
11              public const String strConst = "Const Changed";  
12              public static readonly String strStaticReadonly = "StaticReadonly Changed";  
13        }  
14 } 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM