之前對於Break和Continue;ReadOnly和Const;ref和out,params之類的基礎東東學習過,但是一直沒有仔細去研究到底是怎麼一回事兒,最近在開發中用到了,仔細來做個總結:
1、Break和Continue
//break是跳出整個循環體,不再執行本循環,continue是結束單次循環,繼續下一次循環。 //更多問題 聯系QQ 931697811(夜雨梧桐)
1 #region Break測試 2 3 Console.WriteLine("========Break========"); 4 int x = 0; 5 while (x++ < 20) 6 { 7 if (x == 3) 8 { 9 break; 10 } 11 Console.WriteLine("{0}\n",x); 12 } 13 #endregionView Code
1 #region Continue測試 2 Console.WriteLine("========Continue========"); 3 int k = 0; 4 while (k++ < 10) 5 { 6 if (k == 3) 7 { 8 continue; 9 } 10 Console.WriteLine("{0}\n",k); 11 } 12 #endregionView Code
2、ReadOnly和Const
//有問題:聯系QQ 931697811
1. const修飾的常量在聲明的時候必須初始化;readonly修飾的常量則可以延遲到構造函數初始化
2. const修飾的常量在編譯期間就被解析,即常量值被替換成初始化的值;readonly修飾的常量則延遲到運行的時候
3. 此外const常量既可以聲明在類中也可以在函數體內,但是static readonly常量只能聲明在類中。
1 #region ReadOnly 2 static readonly int A = B * 10; 3 static readonly int B = 10; 4 5 const int j = k * 10; 6 const int k = 10; 7 8 static void Main(string[] args) 9 { 10 Console.WriteLine("===Readonly輸出的值是:==="); 11 Console.WriteLine("A is {0}.B is {1}", A, B); 12 Console.WriteLine("===Const輸出的值是:==="); 13 Console.WriteLine("j is {0}.k is {1}", j, k); 14 Console.ReadKey(); 15 } 16 #endregionView Code
3、ref和out,params
問題的引出:
現需要通過一個叫Swap的方法交換a,b兩個變量的值。交換前a=1,b=2,斷言:交換後a=2,b=1
現編碼如下:
1 1class Program 2 2 { 3 3 static void Main(string[] args) 4 4 { 5 5 int a = 1; 6 6 int b = 2; 7 7 Console.WriteLine("交換前\ta={0}\tb={1}\t",a,b); 8 8 Swap(a,b); 9 9 Console.WriteLine("交換後\ta={0}\tb={1}\t",a,b); 10 10 Console.Read(); 11 11 } 12 12 //交換a,b兩個變量的值 13 13 private static void Swap(int a,int b) 14 14 { 15 15 int temp = a; 16 16 a = b; 17 17 b = temp; 18 18 Console.WriteLine("方法內\ta={0}\tb={1}\t",a,b); 19 19 } 20 20 }View Code
運行結果:
交換前 a = 1 b = 2
方法內 a = 2 b = 1
交換後 a = 1 b = 2
並未達到我們的需求!
原因分析:int類型為值類型,它存在於線程的堆棧中。當調用Swap(a,b)方法時,相當於把a,b的值(即1,2)拷貝一份,然後在方法內交換這兩個值。交換完後,a還是原來的a,b還是原來的b。這就是C#中按值傳遞的原理,傳遞的是變量所對應數據的一個拷貝,而非引用。
修改代碼如下即可實現我們想要的結果:
1 class Program 2 2 { 3 3 static void Main(string[] args) 4 4 { 5 5 int a = 1; 6 6 int b = 2; 7 7 Console.WriteLine("交換前\ta={0}\tb={1}\t",a,b); 8 8 Swap(ref a,ref b); 9 9 Console.WriteLine("交換後\ta={0}\tb={1}\t",a,b); 10 10 Console.Read(); 11 11 } 12 12 //交換a,b兩個變量的值 13 13 private static void Swap(ref int a, ref int b) 14 14 { 15 15 int temp = a; 16 16 a = b; 17 17 b = temp; 18 18 Console.WriteLine("方法內\ta={0}\tb={1}\t",a,b); 19 19 } 20 20 }View Code
1 關於重載
原則:有out|ref關鍵字的方法可以與無out和ref關鍵字的方法構成重載;但如想在out和ref間重載,編譯器將提示:不能定義僅在ref和out的上的方法重載
2 關於調用前初始值
原則:ref作為參數的函數在調用前,實參必須賦初始值。否則編譯器將提示:使用了未賦值的局部變量;
out作為參數的函數在調用前,實參可以不賦初始值。
3 關於在函數內,引入的參數初始值問題
原則:在被調用函數內,out引入的參數在返回前至少賦值一次,否則編譯器將提示:使用了未賦值的out參數;
在被調用函數內,ref引入的參數在返回前不必為其賦初值。
總結:C#中的ref和out提供了值類型按引用進行傳遞的解決方案,當然引用類型也可以用ref和out修飾,但這樣已經失去了意義。因為引用數據類型本來就是傳遞的引用本身而非值的拷貝。ref和out關鍵字將告訴編譯器,現在傳遞的是參數的地址而不是參數本身,這和引用類型默認的傳遞方式是一樣的。同時,編譯器不允許out和ref之間構成重載,又充分說明out和ref的區別僅是編譯器角度的,他們生成的IL代碼是一樣的。有人或許疑問,和我剛開始學習的時候一樣的疑惑:值類型在托管堆中不會分配內存,為什麼可以按地址進行傳遞呢?值類型雖然活在線程的堆棧中,它本身代表的就是數據本身(而區別於引用數據類型本身不代表數據而是指向一個內存引用),但是值類型也有它自己的地址,即指針,現在用ref和out修飾後,傳遞的就是這個指針,所以可以實現修改後a,b的值真正的交換。這就是ref和out給我們帶來的好處。
關於更多如This,Base等下次再分享
const 的概念就是一個包含不能修改的值的變量。
常數表達式是在編譯時可被完全計算的表達式。因此不能從一個變量中提取的值來初始化常量。
如果 const int a = b+1;b是一個變量,顯然不能再編譯時就計算出結果,所以常量是不可以用變量來初始化的。
readonly 允許把一個字段設置成常量,但可以執行一些運算,可以確定它的初始值。
因為 readonly 是在計算時執行的,當然它可以用某些變量初始化。
readonly 是實例成員,所以不同的實例可以有不同的常量值,這使readonly更靈活。
readonly 關鍵字與 const 關鍵字不同。
1. const 字段只能在該字段的聲明中初始化。
readonly 字段可以在聲明或構造函數中初始化。因此,根據所使用的構造函數,readonly 字段可能具有不同的值。
2. const 字段是編譯時常數,而 readonly 字段可用於運行時常數。
3. const 默認就是靜態的,而 readonly 如果設置成靜態的就必須顯示聲明。
4.const 對於引用類型的常數,可能的值只能是 string 和 null。
readonly可以是任何類型
* 需要注意的一個問題是:
對於一個 readonly 的 Reference 類型,只是被限定不能進行賦值(寫)操作而已。而對其成員的讀寫仍然是不受限制的。
public static readonly Class1 my = new Class1();
…
my.SomeProperty = 10; //正常
my = new Class1(); //出錯,該對象是只讀的
但是,如果上例中的 Class1 不是一個 Class 而是一個 struct,那麼後面的兩個語句就都會出錯。
static readonly:
Java 中 static 是當載入一個類時執行一次的。
C#中是怎麼執行的,我沒有查到。很奇怪幾乎每本java的書都會說static的問題,C#的往往只說怎麼用,但是應該是在main函數調用之前初始化,所以static readonly也是運行時的,可以用變量付值,如:
private static readonly string path = System.Windows.Forms.Application.StartupPath + “aaa”;
const 的概念就是一個包含不能修改的值的變量。
常數表達式是在編譯時可被完全計算的表達式。因此不能從一個變量中提取的值來初始化常量。
如果 const int a = b+1;b是一個變量,顯然不能再編譯時就計算出結果,所以常量是不可以用變量來初始化的。
readonly 允許把一個字段設置成常量,但可以執行一些運算,可以確定它的初始值。
因為 readonly 是在計算時執行的,當然它可以用某些變量初始化。
readonly 是實例成員,所以不同的實例可以有不同的常量值,這使readonly更靈活。
readonly 關鍵字與 const 關鍵字不同。
1. const 字段只能在該字段的聲明中初始化。
readonly 字段可以在聲明或構造函數中初始化。因此,根據所使用的構造函數,readonly 字段可能具有不同的值。
2. const 字段是編譯時常數,而 readonly 字段可用於運行時常數。
3. const 默認就是靜態的,而 readonly 如果設置成靜態的就必須顯示聲明。
4.const 對於引用類型的常數,可能的值只能是 string 和 null。
readonly可以是任何類型
總結
const只能在初期就使用常量初始化好。對於每一次編譯後的結果,const的值是固定的,而readonly的值是可以在運行的時候才確定值的~~