我並不是不聞不問![C#]
Written by Allen Lee
我在《我只負責轉換![C/C++]》一文從類型轉換的角度展示了C/C++對程式員的信任,那麼C#對程式員的信任程度又有多高呢?
我們先來看一段C#代碼:
// Code #01
public enum Alignment
{
Left,
Center,
Right
}
class Program
{
static void Main()
{
Alignment a = (Alignment)(-1);
Console.WriteLine(a);
a = 0;
Console.WriteLine(a);
a = (Alignment)(1);
Console.WriteLine(a);
a = (Alignment)(2);
Console.WriteLine(a);
a = (Alignment)(3);
Console.WriteLine(a);
}
}
// Output:
//
// -1
// Left
// Center
// Right
// 3
這段代碼能夠順利編譯並運行。從輸出結果中,我們可以看出C#不會妨礙你進行非預期的枚舉轉換。只是你必須對你的行為進行負責,如果你進行了非預期的轉換,你將得到非預期的輸出;相反,如果轉換是有意義的話,輸出也將是有意義的。另外,0是被自動轉換成對應的枚舉類型,不需要我們動手。
現在來看另一段C#代碼:
// Code #02
public enum Alignment : byte
{
Left,
Center,
Right
}
class Program
{
static void Main()
{
Alignment a = (Alignment)(-1);
Console.WriteLine(a);
}
}
這次,我們為Alignment指定了底層類型,編譯器不再不聞不問了,它拒絕編譯並留下這樣一句話:
error CS0221: Constant value '-1' cannot be converted to a 'Alignment' (use 'unchecked' syntax to override)
跟之前的不同,程式員不應該由於疏忽導致這種溢出,如果你是有意這樣做的,必須用unchecked文法明確告訴編譯器:
// Code #03
// See Code #02 for Alignment.
class Program
{
static void Main(string[] args)
{
unchecked
{
Alignment a = (Alignment)(-1);
Console.WriteLine(a);
}
}
}
// Output:
//
// 255
這次編譯器就不抱怨了,不過,你也應該認真想一下,這種溢出轉換是否真的有必要呢?
那麼,這種溢出轉換在C++的國度又是怎樣一番景象呢?請先看下面的C++代碼:
// Code #04
#include string>
#include iostream>
enum _jb_prog_mode : unsigned short
{
PROGRAM_ONE,
PROGRAM_TWO
};
int _tmain(int argc, _TCHAR* argv[])
{
// In C, the enum keyword is required
// to declare a variable of type enumeration.
// In C++, the enum keyword can be omitted.
// The following expression is legal in C++ only.
_jb_prog_mode e_prog_index = (_jb_prog_mode)(-1);
std::cout (unsigned short)e_prog_index std::endl;
return 0;
}
// Output:
//
// 65535
這段代碼能夠正常編譯並順利運行。從輸出結果中我們明顯看到溢出,但編譯器和運行時卻沒有半點鐘聲響。看來,C++對程式員的信任程度真的去到了巔峰之處。
請注意,ANSI C不允許我們指定枚舉的底層類型,所有枚舉的底層類型都是int。
接下來我們看看註冊表的讀取,假定註冊表有如下資訊:
[HKEY_LOCAL_MACHINE\SOFTWARE\Allen]
"Name"="Allen Lee"
"ID"=dword:00000584
然後我們來看看下面的C#代碼:
// Code #05
class Program
{
static void Main(string[] args)
{
RegistryKey rk = Registry.LocalMachine.OpenSubKey("software\\Allen");
object obj = rk.GetValue("Name");
string nm = (string)obj; // Convert_01
// int nm = (int)obj; // Convert_02
Console.WriteLine(nm);
obj = rk.GetValue("ID");
int id = (int)obj; // Convert_03
// string id = (string)obj; // Convert_04
Console.WriteLine(id);
}
}
// Output:
//
// Allen Lee
// 1412
上面這段代碼當然可以正常輸出正確的結果。如果我們分別把Convert_01和Convert_03替換為Convert_02和Convert_04呢?編譯器不會拒絕你的編譯請求,但運行時會毫不猶豫地拋出InvalidCastException,並指出無法進行指定的類型轉換。
那麼,C++在面對類似的情況又是如何應付的呢?有興趣的朋友可以參照《我只負責轉換![C/C++]》一文中給出的代碼片斷實驗一下,你將體會到C++對程式員是何等的信任!
結論?也正如本文的題目——
我並不是不聞不問!
與C/C++比起來,C#的確沒有那麼自由,然而,這些限制卻為我們帶來另一番的味道。究竟C#的這些限制是對我們的一種協助還是一種縛束呢?這就見仁見智了。
See also:
- Allen Lee;《我只負責轉換![C/C++]》
- Allen Lee;《關於枚舉的種種 (Enumeration FAQ) [C#, IL, BCL]》