array的初始化
byte[] tmpArray = new byte[14];
Array.Clear(tmpArray, 0, 14); //array的初始化之一,值為0
tmpArray = Enumerable.Repeat((byte)0xFF, tmpArray.Length).ToArray<byte>(); //array的初始化之二,值為0xFF
一、Object's finalizer and Dispose
跟 Java 一樣,在 C# 也使用了記憶體自動回收機制(Garbage Collection),因此以往 C++ 中釋放物件時所執行的解構子(destructor),在 C# 稱為 finalizer,finalizer 會在該物件實體將被 CLR 回收時執行,此外,由於開發者無法強制 CLR 執行記憶體回收,因此 finalizer 確切的執行時間是不能控制的。
1
2
3
4
class
A {
public
A() { ... } // constructor
~A() { ... } // finalizer,寫法與 C++ destructor 一樣
}
IDisposable 介面只有定義一個方法 -「void Dispose()」,任何實作 IDisposable 的類別都必須覆載 Dispose 方法,程式設計師可在 Dispose 中撰寫關閉串流或其他資源的程式碼,但是問題在於 Dispose 方法的執行時機,它是由程式設計師「自行呼叫」的(即撰寫 物件.Dispose() ),看到這裡可能會覺得很可笑,我大可自行定義一個方法來關閉資源,難道只為了統一方法名稱就必須實作 IDisposable 介面!不是這樣的,使用 using statement 可以讓你更方便!
1
2
3
4
5
6
// 實作 IDisposable 的類別
class
A : IDisposable { public
void
Dispose() { ... } }
using
(A a = new
A()) { // 將實作 IDisposable 的類別在此實體化
...
}
// 到 } 後(或是 a 為 null),系統會自動呼叫 a 物件的 Dispose 方法,程式設計師不用自行呼叫
二、C# 中的 struct
C# 保留了 C/C++ 的 struct(結構)語法,此外也賦予 struct 可擁有成員變數、成員方法(即定義資料與操作),就像類別一樣。
01
02
03
04
05
06
07
08
09
10
11
// struct 可實作介面,但「不能繼承」
public
struct
AlmostSuperhero : IDisposable {
// struct 可定義成員變數
public
int
leng;
// struct 可擁有 property
public
int
SuperSpeed { get; private
set; }
// struct 可定義方法
public
void
Dispose() { ... }
}
// 如同物件一般的創建
AlmostSuperhero structObj = new
AlmostSuperhero();
雖然 struct 與 object 如此相像,它們有關鍵性的不同:記憶體配置的方式不同!object 是配置在「Heap」,struct 實體則配置在「Stack」。你也許還沒感受到事情的嚴重性。看看以下的例子吧!
1
2
3
4
5
6
AlmostSuperhero a = new
AlmostSuperhero();
a.leng = 10;
AlmostSuperhero b = a; // struct 的指派是「複製」
b.leng = 20;
Console.WriteLine("a's leng is {0}, b's leng is {1}", a.leng, b.leng);
// 結果: a's leng is 10, b's leng is 20
上述例子中,如果 AlmostSuperhero 是類別的話,那結果就不一樣了:a's leng is 20, b's leng is 20。這是因為 object 的指派是派址,因此 a 與 b 將指向同一個物件,而 struct 則是將 a 複製一份給 b,因此改變 b 的狀態,a 就不會隨之改變。
struct 不能繼承任何 struct 或 class,但是可以實作介面。
配置於 Stack: int、double、string ...(基本型態)
配置於 Heap: String 與其他類別
還有一個東西我們沒有提到!「Boxing、Unboxing 機制」。 這是什麼東西?也許你會想問:如果我把 struct 實體指派給 class 型態那會怎麼樣?編譯器似乎沒給我任何抱怨,而且也可以執行!沒錯!這就要歸功於 Boxing 與 Unboxing 的幫忙了。當你把配置於 Stack 的 struct 實體指派給 class 型態,CLR 會將該 struct 複製一份並利用 Boxing 機制包裹起來丟到 Heap 中,再指定給 class 型態的變數。反之再把 Boxing 後的物件指定回 struct 則稱作 Unboxing。不同點是:Boxing 是隱性轉型(implicit cast),而 Unboxing 必須寫明,屬於顯性轉換(explicit cast)。
1
2
3
int
foo = 42; // Value type
object
bar = foo; // foo 透過 boxing 轉為 bar(implicit cast)
int
foo2 = (int)bar; // 透過 unboxing 轉回 int(explicit cast)
2. Formatting
Formatting 是將數字轉化成字串時,順便將其格式化,舉個例來講:有一浮點數 float pi = 3.14159265f; 將其轉化成 3 位小數的字串則用 pi.ToString("f3"); 即可。下列是一些常用的轉化格式:
c ---> 當地貨幣
f3 ---> 3 位小數
0 ---> 整數
n ---> 每 3 位數一個 ","
0% ---> 整數百分比
is 運算 => 判斷型別(回傳 true or false)
as 運算 => 物件轉型
sealed 修飾子 => 被標示為 sealed 的 class 就無法被繼承了