1. 程式人生 > 其它 >c# sbyte string轉_C# 學習之路(八)

c# sbyte string轉_C# 學習之路(八)

技術標籤:c# sbyte string轉

列舉、結構與陣列

本系列文章主要意在鞏固筆者在學習過程中學到的有關 C# 特性的知識,分享 C# 中較為重要和突出的部分和有助養成良好程式設計習慣的提示。

並非旨在系統介紹 C#。


今天的文章主要介紹具有 C# 特性的或者比較重要的,有關列舉、結構與陣列的知識。明天咕咕一天,最近快開學了要準備期末考試,沒辦法寫的太多faf4626d2d6b3fb19befac68796af476.png。為了儘量避免文章中出現不當的、有事實性錯誤的例子或解釋,筆者會多多查閱資料,加深自己的理解!歡迎大家通過公眾號留言的方式指出文章中存在的錯誤,筆者會盡快檢查並更正的,感謝!

迭代器,永遠滴神!列舉器,永遠滴看不懂!


目錄:

  • 有關列舉的小知識

  • 有關結構的小知識

  • 有關陣列的小知識


有關列舉的小知識:

本條目不旨在系統介紹相關知識,下同。

列舉的宣告:

enumSeason{Spring,Summer,Fall,Winter}

列舉內部每個的每個元素都關聯(對應)一個整數值。預設第一個值對應整數 0,之後每個元素的值在前一個元素的基礎上遞增 1。此處的 Spring對應 0,Summer 對應 1,Fall 對應 2,Winter 對應 3。

可為任意一個列舉值顯式指定對應整數值:

enum Season { Spring = 1, Summer, Fall, Winter}

具有相同含義的列舉值可共用一個值:

enum Season { Spring, Summer, Autumn = Fall, Winter}

宣告列舉時,列舉字面值預設為 int 型別。可以讓列舉型別基於不同的基礎型別:

enum Season : short { Spring, Summer, Fall, Winter}

列舉只可基於整型,包括:byte,sbyte,short,ushort,int,uint,long, ulong

對列舉變數執行數學運算(如遞增),會改變這個變數的內部整數值。


有關結構的小知識:

類定義的是引用型別,總是在堆上建立。有時類只包含極少數據,因為管理堆而產生的開銷不合算。這時更好的做法是使用結構。結構是值型別,在棧上儲存,能有效減少記憶體管理的開銷(當然前提是結構足夠小)。

在 C# 的基元型別中,只有 string 和 object 是類,其餘均為結構。例如,int 是 System.Int32結構的別名,double 是 System.Double結構的別名。

對於簡單的、比較小的資料值,如果複製值的效率等同於或基本等同於複製引用的效率,就用結構,但是,較複雜的資料就要考慮使用類。這樣就可選擇只複製資料的地址,從而提高程式碼的執行效率。

需要注意的是,不能為結構宣告預設構造器(即無參構造器)。

structUzi{publicTime(){}//編譯時錯誤}//不同於 C++,C#中的結構可包含帶有訪問限制字首的欄位、方法,甚至構造器。

之所以不能為結構宣告預設構造器,是因為編譯器始終都會自動生成一個預設構造器。這點不同於類,在類中,只有在沒有自己寫構造器的時候編譯器才會自動生成一個預設構造器。

確有必要寫自己的帶參構造器時,需要在其中顯示初始化所有欄位,否則會有編譯錯誤。

結構的初始化:

Uzi jianZiHao = new Uzi();

需要注意,雖然此處使用了 new 關鍵字,但結構仍然位於棧上,這點不同於類。而由於整個結構都位於棧上,因此使用賦值號對兩結構進行如下複製時:

UzijianZiHao=new Uzi();UzixiaoHu=jianZiHao;

賦值號將對整個結構的內容進行復制,而不是像類那樣只複製一個引用。這個複製過程絕對不可能丟擲異常。將一個整型變數包含的值賦值給另一個整型變數,賦值之後將存在兩個整型變數,只不過具有相同的值,結構的複製具有類似性質。


有關陣列的小知識:

陣列是無序的元素序列。陣列中的所有元素都具有相同型別(下一篇就淺析一下泛型吧!)。陣列中的元素儲存在一個連續性的記憶體塊中,並通過索引來訪問。

宣告陣列:

int[]pins;//pins是PersonalIdentificationNumbers(個人識別號)的簡稱

先寫元素型別名稱,後跟一對方括號,最後寫變數名。這樣,一道陣列就做好了,隔壁小孩都饞哭了。需要注意,陣列大小在 C# 中並不是陣列的一部分。

陣列元素可以是基元資料型別、列舉、結構或類。無論元素是什麼型別,陣列變數始終都是引用型別。這意味著陣列變數(上例中 pins)引用堆上的記憶體塊,陣列元素存在這個記憶體塊中,這種行為類似類變數引用堆上物件。即使陣列元素是int 這樣的值型別,也是在堆上分配記憶體。

宣告類變數時不會馬上為物件分配記憶體,用 new 關鍵字建立物件時才會。陣列也是如此,宣告陣列時不需要馬上指定大小,也不會分配堆記憶體(只會在棧上分配一小塊用於儲存引用的記憶體,類似類變數)。建立陣列例項時才分配記憶體,陣列大小在此時指定

pins = new int[4]; // 初始化陣列

建立陣列例項時,會用預設值(0,null 或 false,取決於元素型別)對陣列元素初始化。當然,可以用指定的值初始化陣列:

int[]pins=newint[4]{4,3,9,6};//不針對廠長,單純借用這個魔術數字

大括號內的值不一定是常量,可以為表示式。大括號中的值的數量必須要和陣列的元素數量相匹配。

int[] pins = new int[4]{ 4, 3, 9, 6 }; // 不針對廠長,單純借用這個魔術數字int[]pins=newint[4]{4,3,9};//非法int[] pins = new int[3]{ 4, 3, 9 }; // 合法

當然,可通過預設 new 表示式和陣列大小的方式來讓編譯器根據初始值數量來計算大小,並生成程式碼來建立陣列:

int[]pins={4,3,9};//合法,定義並初始化一個大小為 3 的整型陣列

C# 學習之路(一)中介紹了 var 關鍵字,在宣告陣列時,我們也可以利用 var 關鍵字,通過用於初始化元素的值,讓編譯器判斷這是個什麼型別的陣列:

varnames=new[]{"John","Diana","Moly","Zion"}; int[] pins = new int[4]{ 4, 3, 9, 6 }; // 常規方法

用這種方式宣告陣列,語法上有所不同。

即使使用 var 宣告陣列,仍然需要注意所有初始值具有相同型別,否則會導致編譯器報錯。要記住,陣列中的所有元素都具有相同型別噢!(除非你宣告object 陣列)

但是,在極個別特殊情況下,編譯器會把不同型別的元素轉換為相同型別——前提是有意義:

varnumbers=new[]{1,2,3.5,99.999};

上例中,編譯器會將 1和 2 轉換為 double。需要注意,在 C# 中,1 就是 1,1.0 就是 1.0,兩者是不同型別的。當然,上述寫法是不推薦的。不應指望編譯器幫自己轉換型別,這樣會寫出難以理解的程式碼。
隱式型別陣列尤其適合匿名型別,藉助隱式型別陣列和匿名型別,我們可以寫出如下程式碼:

varname=new[]{new{Name="John",Age=10}, // 匿名類作元素new{Name="Diana",Age=50},new{Name="Moly",Age=3},new{Name="Zion",Age=10086} };

這種寫法簡潔且具有實用性,其中的元素是相同的匿名類(還記得如何判斷匿名類是否型別相同嗎?)。

和 C++ 相同,陣列第一個元素的索引是 0 而不是 1,索引用於訪問陣列元素,語法如下:

int[] pins = new int[4]{ 4, 3, 9, 6 };Console.WriteLine(pins[0]);//輸出陣列第一個元素

上述程式碼中利用索引 0 訪問陣列第一個元素 4。

(pins[0]==4);//訪問陣列第一個元素(pins[1] == 3); // 訪問陣列第二個元素(pins[2] == 9); // 訪問陣列第三個元素(pins[3]==6);//訪問陣列第四個元素

以上布林表示式均為 true,它們表達了索引和陣列元素之間的關係。索引用於訪問陣列元素。

C# 提供 foreach 語句遍歷陣列:

int[] pins = new int[4]{ 4, 3, 9, 6 };foreach(intpininpins){Console.WriteLine(pin);}

上例中foreach 語句等價於以下 for 語句:

for(intindex=0;index{intpin=pins[index];Console.WriteLine(pin);}

foreach 語句聲明瞭一個迴圈變數(此處為 int pin)來自動獲取陣列中每個元素的值。該變數的型別必須與陣列元素型別匹配。foreach 語句是遍歷陣列的首選方式,它更明確且簡潔。但少數情況使用 for 迴圈來遍歷陣列是更合理的選擇:

  • foreach語句總是遍歷整個陣列,無法跳過單獨的元素或遍歷陣列的一部分。

  • foreach 語句總是從索引為 0 到索引為 Lenth - 1遍歷陣列,無法以其他方式遍歷陣列。

  • 如迴圈主體需要元素索引而非元素值,則應使用 for 迴圈。(foreach 語句中不出現索引)

  • 修改陣列元素必須使用 for 語句。因為 foreach 語句中使用的是陣列元素的只讀拷貝。

另外,陣列可作為方法引數或者返回值:

public void Set(int[] data){}publicint[]ReadMe(){}

需要記住,陣列是引用型別,在方法內修改陣列,等價於修改原陣列。

可利用方法CopyTo 複製整個陣列(不只是引用!):

int[]pins={4,3,9, 6 };int[]copy=newint[pins.Lenth];pins.CopyTo(copy, 0); // 引數 0 表示從索引 0 開始複製元素到目標陣列。

這樣我們會得到兩個相同的陣列,且 pins 與 copy 引用的是不同的陣列,而非使用賦值語句導致兩變數引用同一陣列。

靜態方法 Copy 可以起到同樣作用:

int[] pins = { 4, 3, 9, 6 };int[] copy = new int[pins.Lenth];Array.Copy(pins, copy, copy.Lenth);

多維陣列:

如下宣告二維陣列:

int[,]items=newint[4, 6];

二維陣列提供了兩個索引,具有強大功能。多維陣列的宣告與上例類似,無非加幾個逗號和陣列在某一維度上的大小。

如下訪問二維陣列:

items[2,3]=99;//設定座標(2,3)的陣列元素值為99items[2, 4] = items[2, 3]; // 設定座標(2,4)的陣列元素值與座標(2,3)的陣列元素值相同

使用多維陣列要小心記憶體佔用過大記憶體。提防 OutOfMemoryException 異常。

交錯陣列:

在 C# 中,普通多維陣列有時稱為矩形陣列。多維陣列有時可能消耗大量記憶體。比如一個二維陣列,在第一個維度上的大小是 4,在第二個維度上的大小是 40。假設第一個維度的座標 0 上,我們需要填入 35 個元素;第一個維度的座標 1 上,我們需要填入 25 個元素;第一個維度的座標 2 上,我們需要填入 5 個元素;第一個維度的座標 3 上,我們需要填入 30 個元素。那麼這樣,我們就整整浪費了 5 + 15 + 35 + 10 個元素所佔用的空間!因為我們根本不需要填入這些元素(相當於圖中的白色部分)!此時矩形陣列就具有很大劣勢,我們就需要使用交錯陣列。

21edcea86aa518503533923eac39e040.png

交錯陣列的定義:

int[][]items=newint[4][];//指定第一個維度的大小為 4int[]columnForRow0=newint[35];//指定座標 0 需要的陣列大小int[]columnForRow1=newint[25];//指定座標1需要的陣列大小int[]columnForRow2=newint[5];//指定座標2需要的陣列大小int[]columnForRow3=newint[30];//指定座標3需要的陣列大小items[0]=columnForRow0;//向陣列中填入陣列items[1] = columnForRow1;items[2] = columnForRow2;items[3] = columnForRow3;

事實上,我們可以將交錯陣列理解為陣列的陣列。在上例中,我們相當於定義了一個有四個元素的陣列,它其中的元素都是整型陣列,只不過作為元素的陣列的大小不同罷了。

本文中C#的有關知識整理歸納改編自《VisualC#從入門到精通(第九版)》清華大學出版社JohnSharp著周靖譯ISBN978-7-302-51624-8十分推薦想學習C#的朋友購入學習

筆者水平有限,如有錯誤,歡迎給公眾號留言反饋(文章目前不支援留言)ef50e1456b7d62bf834beda978a02afd.png