C#語言基礎常見問題匯總
概述
1、什么是C#?
C#是Microsoft公司設計的一種編程語言。它松散地基于C/C++,并且有很多方面和Java類似。
Microsoft是這樣描述C#的:“C#是從C和C++派生來的一種簡單、現代、面向對象和類型安全的編程語言。C#(讀做‘Csharp’)主要是從C/C++編程語言家族移植過來的,C和C++的程序員會馬上熟悉它。C#試圖結合Visual Basic的快速開發能力和C++的強大靈活的能力。”
2、如何開發C#應用程序?
.NET SDK包括了C#命令行編譯器(csc.exe),下一個版本的Visual Studio (Visual Studio 7 or Visual Studio.NET)會包含對C#開發的完整支持。
3、C#可以取代Java?
C#非常像Java語言——這兩種語言的核心和C++相比都有相似的優缺點。例如,兩個語言都有垃圾回收,但是兩個語言都沒有模板(template)。Microsoft已經中止了Visual J++產品,因此很難不認為Microsoft在使用C#來替代Java。
4、C#可以取代C++?
顯然是不,但是我們又很難說C++是新的.NET平臺上編寫代碼的最佳選擇。為了使.NET的運行層能完全發揮作用,它要求編程語言遵循某些特定的規則——其中之一就是所有的語言類型必須遵守通用類型系統(Common Type System,CTS)。不幸的是,許多C++特性不能被CTS支持。例如,模板和類的多重繼承。
Microsoft對這個問題的答案是給C++提供可管理的擴展(Managed Extensions,ME), 這可以使C++遵守CTS。通過添加新的關鍵字來標記C++類有CTS的屬性(例如.-gc表示垃圾回收)。但是在創建新的工程時很難講為什么ME C++會比C#更合適。就特征(feature)而言它們很相似,但與C++不同的是C#從一開始就以.NET為環境設計的。ME C++存在的理由好像是將C++代碼移植(port)為.NET環境下的代碼。
因此,這個問題的答案,很可能是C++作為一個.NET環境之外的語言將依然保留它的重要性;而通過ME將現存的C++代碼移植為適合.NET環境;但是很可能C#將是C++開發者開發新的.NET應用程序的最好選擇。
8、C#是面向對象的嗎?
是的,C#像Java和C++一樣,是一個面向對象的語言。
9、C#有自己的類庫嗎?
不,就像所有的.NET語言(VB.Net,JScript .Net...)一樣,C#訪問.NET類庫,C#沒有自己的類庫。
基本類型
1、C#提供什么標準類型?
C# 支持的基本類型和C++很相似,包括int, long, float, double, char, string, arrays, structs 和 classes。然而,不要假設太多,名字可能很形似,但是一些細節不相同。例如C#中的long是64位的,而C++的long取決于平臺,32位的平臺上是32位的,64位的平臺上是64位的。class和struct在C++中幾乎完全一樣,但在C#中并不是這樣的。
2、是否所有的C#類型都派生于一個公共的基類?
是,也不是,所有的對象都可以看作從Object (System.Object)派生而來。但是為了把像int,float這樣的值類型實例看作是從Object對象派生的,這個實例必須通過一個裝箱的操作(boxing)轉化為引用類型。理論上,開發者可以忽略這些底層的轉化,但是認識到這點對于系統性能影響很重要。
3、是否可以這樣認為,可以將一個值類型的實例作為參數傳給以對象為參數的方法?
是的,例如:
class CApplication { public static void Main() { int x = 25; string s = “fred”; DisplayMe( x ); DisplayMe( s ); } static void DisplayMe( object o ) { System.Console.WriteLine( “You are {0}”, o ); } }
將顯示:
You are 25
You are fred
4、值類型和引用類型的最基本的區別是什么?
C#將類型分為兩類,一類是值類型,另一類是引用類型。大部分固有的基本類型(如int, char)是值類型,structs 也是值類型。引用類型包括類、接口、數組和字符串。基本的概念非常簡單,那就是一個值類型的實例代表了實際的數據(存在棧中),而一個引用類型的實例代表指向數據的指針或者引用(存在堆中)。
C++開發者最容易混淆的地方是:C#已經自己預定義了一些類型作為值類型,一些作為引用類型,而一個C++的開發者希望能夠自己控制。
例如,在C++中,我們可以這樣做:
int x1 = 3; // x1 是堆棧上的值
int *x2 = new int(3) // x2 是堆的一個值的引用
但是在C#中沒有這樣的控制:
int x1 = 3; // x1是堆棧上的值
int x2 = new int();
x2 = 3; // x2還是堆棧上的值!
5、既然 int是值類型,而 class是引用類型,那么int是怎樣從Object派生的呢?
是這樣的,當int用作int時候,這是一個值類型(在棧上),然而,當它用作是Object時,這是一個引用堆上的整數值的引用類型。換而言之,當你將int看作對象時,運行層將它自動轉化為對象引用,這個轉化過程稱作裝箱(boxing)。這個轉換包括將棧里的值拷貝到了堆里,并且新建了一個對象的實例來引用該值。拆箱操作(unboxing)是個反過程——將對象轉化為基于棧的值類型。
int x = 3;
// 堆棧上新的int類型,值為3
object objx = x;
// 堆上新的int, 設定值為3,x=3仍然在堆棧上
int y = (int)objx;
//新的int類型的值3在堆棧上,x=3在堆棧上,objx=3在堆上
6、C#使用引用替代指針,那么C#的引用和C++的引用一樣嗎?
不完全,基本的思想是一樣的,但是一個重要的區別是C#的引用可以是null。因此你不能確認C#的引用一定會是一個有效的對象。如果試圖使用一個值為null的引用,一個NullReferenceException 異常將被拋出。
例如,看一看以下的方法:
void displayStringLength( string s ) { Console.WriteLine( “String is length {0}”, s.Length ); } 如果這樣調用它,這種方法將產生一個NullReferenceException 異常: string s = null; displayStringLength( s ); 當然有些情況你認為產生這樣一個異常是完全可以接受的結果, 但是在這個例子里最好按下面的代碼改寫一下: void displayStringLength( string s ) { if( s == null ) Console.WriteLine(“String is null”); else Console.WriteLine(“String is length {0}”, s.Length ); }
class和struct
1、struct在C++中是多余的,為什么C#還要使用它們呢?
在C++中,一個結構和一個類幾乎就是一個同樣的東西。唯一的區別是缺省的成員的訪問級別不一樣(struct的缺省級別是public,class的缺省級別是private)。然而,在C#中struct和class完全不一樣。在C#中,struct 是值類型,而class是引用類型。另外struct不能從其他struct或者class繼承,盡管struct可以實現接口。struct沒有析構器。
2、C#支持多重繼承嗎?
C#支持接口的多重繼承,但是不支持類的多重繼承。
3、C#接口和C++抽象類一樣嗎?
不,不完全。C++的抽象類不能被實例化。但是它可以(而且經常是)包含執行代碼和數據成員。一個C#接口不能包含任何執行代碼或數據成員,它只是一組方法名稱和簽名(signature)。一個C#的接口更像是一個COM接口而不是抽象類。
另一個主要的不同點是:C#類只能從一個類(不管是否抽象)繼承,但可以實現多重接口。
4、C#構造器和C++ 構造器是否相同?
非常相似,但是它們絕對不同。第一,C#析構器不保證在某個特定的時間被調用。實際上它根本不保證被調用。真實的情況是,C#析構器只是一個偽裝了的Finalize方法。具體點講,它是一個插入調用基類Finalize方法的Finalize方法。因此,這段代碼:
class CTest { ~CTest() { System.Console.WriteLine(“Bye bye” ); } } 實際上就是: class CTest { protected override void Finalize() { System.Console.WriteLine(“Bye bye” ); base.Finalize(); } }
如果你不相信,可以將一個 Finalize方法和一個析構器加入C#類中,然后就可以知道是如何編譯的了。
5、什么是靜態構造器?
它是整個類的一個構造器,而不是類的一個實例的構造器,它在類裝載的時候被調用。
6、C#中所有的方法都是虛方法嗎?
不,像C++一樣,缺省的時候,方法不是虛擬的,但都可以改為虛擬的。
7、怎樣在C#中聲明一個純虛函數?
在方法前使用abstract修飾符,類也可以標記為abstract(這是自然的)。注意,abstract方法不能有執行代碼(不同于C++中純虛方法)。
和C++處理的不同
1. 我“new”了一個對象,但是我怎樣刪除它?
你不能,不允許你顯式地調用析構器,也沒有delete操作符。但是不必擔心,垃圾回收(garbage collection)會釋放你的對象,最終會的(也許會的)。
2. 我試圖在棧上建立一個對象,但是C#編譯器不通過,這是怎么回事?
和C++不同,你不能在棧上建立一個對象的實例。類的實例總是被建立在堆上并且接受垃圾回收器(garbage collection)的管理。
3. 我定義了一個析構器,但是它從來不能被調用,為什么?
一個C#析構器實際上是Finalize方法的實現,但是運行環境不保證調用Finalize方法。你可以考慮通過調用GC.RequestFinalizeOnShutdown()方法試一下。
4. 大多數的C#基本類型和C++的基本類型有相同的名字,它們一樣嗎?
不,C#中char和C++中的wchar是相同的。C#中所有的字符包括字符串都是Unicode的,C#中整型值是固定大小的,而在C++中其大小取決于處理器。例如,一個C#的int是32位的,而C++ 中int在32-bit處理器上是32位的,在64-bit處理器上是64位的,一個C#的long是64位的。