C# 基礎加強面試題彙總
1、C#中的委託是什麼?事件是不是一種委託?事件和委託的關係。
委託可以把一個方法作為引數代入另一個方法。
委託可以理解為指向一個函式的指標。
委託和事件沒有可比性,因為委託是型別,事件是物件,下面說的是委託的物件(用委託方式實現的事件)和(標準的event方式實現)事件的區別。事件的內部是用委託實現的。因為對於事件來講,外部只能“註冊自己+=、登出自己-=”,外界不可以登出其他的註冊者,外界不可以主動觸發事件,因此如果用Delegate就沒法進行上面的控制,因此誕生了事件這種語法。事件是用來閹割委託例項的,類比用一個自定義類閹割List。事件只能add、remove自己,不能賦值。事件只能+=、-=,不能= 。加分的補充回答:事件內部就是一個private的委託和add、remove兩個方法
面試聊:用Reflector檢視.Net的類的內部實現,解決問題
2、C#中的介面和類有什麼異同。
答:介面是負責功能的定義,專案中通過介面來規範類,操作類以及抽象類的概念!
而類是負責功能的具體實現!
在類中也有抽象類的定義,抽象類與介面的區別在於:
抽象類是一個不完全的類,類裡面有抽象的方法,屬性,也可以有具體的方法和屬性,需要進一步的專業化。
但介面是一個行為的規範,裡面的所有東西都是抽象的!
一個類只可以繼承一個基類也就是父類,但可以實現多個介面
不同點:
不能直接例項化介面。
介面不包含方法的實現。
介面可以多繼承,類只能單繼承。
類定義可在不同的原始檔之間進行拆分。
相同點:
介面、類和結構都可以從多個介面繼承。
介面類似於抽象基類:繼承介面的任何非抽象型別都必須實現介面的所有成員。
介面和類都可以包含事件、索引器、方法和屬性。
基礎知識:介面只能定義方法(只能定義行為,不能定義實現也就是欄位),因為事件、索引器、屬性本質上都是方法,所以介面中也可以定義事件、索引器、屬性。
3、override與過載(overload)的區別
過載是方法的名稱相同。引數或引數型別不同,進行多次過載以適應不同的需要。過載(overload)是面向過程的概念。
Override 是進行基類中函式的重寫。Override是面向物件的概念
4、屬性和public欄位的區別是什麼?
屬性可以對設值、取值的過程進行非法值控制,比如年齡禁止設值負數,而欄位則不能進行這樣的設定。雖然一般情況下get讀取的值就是set設定的值,但是可以讓get讀取的值不是set設定的值的,極端的例子。Public Age{get{return 100;}set{}}。加分的補充回答:用reflector反編譯可以看出,屬性內部本質上就是set_***、get_***方法,詳細參考傳智播客.net培訓視訊中串講.net基礎的部分。
class Person
{
public int Age
{
get
{
return 3;
}
set
{
}
}
}
Person p1 = new Person();
p1.Age = 30;
p1.Age++;
Console.Write(p1.Age);//輸出3
5.請敘述屬性與索引器的區別。
屬性 索引器
通過名稱標識。 通過簽名標識。
通過簡單名稱或成員訪問來訪問。 通過元素訪問來訪問。
可以為靜態成員或例項成員。 必須為例項成員。
屬性的 get 訪問器沒有引數。
索引器的 get 訪問器具有與索引器相同的形參表。
屬性的set訪問器包含隱式value引數。 除了value 引數外,索引器的 set 訪問器還具有與索引器相同的形參表。
6、請敘述const與readonly的區別。
每一個class至多隻可以定義一個static建構函式,並且不允許增加訪問級別關鍵字,引數列必須為空。
為了不違背編碼規則,通常把static資料成員宣告為private,然後通過statci property提供讀寫訪問。
const 關鍵字用於修改欄位或區域性變數的宣告。它指定欄位或區域性變數的值不能被修改。常數宣告引入給定型別的一個或多個常數。
const資料成員的宣告式必須包含初值,且初值必須是一個常量表達式。因為它是在編譯時就需要完全評估。
const成員可以使用另一個const成員來初始化,前提是兩者之間沒有迴圈依賴。
readonly在執行期評估賦值,使我們得以在確保“只讀訪問”的前提下,把object的初始化動作推遲到執行期進行。
readonly 關鍵字與 const 關鍵字不同: const 欄位只能在該欄位的宣告中初始化。readonly 欄位可以在宣告或建構函式中初始化。因此,根據所使用的建構函式,readonly
欄位可能具有不同的值。另外,const 欄位是編譯時常數,而
readonly 欄位可用於執行時常數。
readonly 只能在宣告時或者建構函式裡面初始化,並且不能在 static 修飾的建構函式裡面。
7、在dotnet中類(class)與結構(struct)的異同?
Class可以被例項化,屬於引用型別,是分配在記憶體的堆上的。類是引用傳遞的。
Struct屬於值型別,是分配在記憶體的棧上的。結構體是複製傳遞的。加分的回答:Int32、Boolean等都屬於結構體。
8、值型別和引用型別的區別?
1.將一個值型別變數賦給另一個值型別變數時,將複製包含的值。引用型別變數的賦值只複製對物件的引用,而不復制物件本身。
2.值型別不可能派生出新的型別:所有的值型別均隱式派生自 System.ValueType。但與引用型別相同的是,結構也可以實現介面。
3.值型別不可能包含 null 值:然而,可空型別功能允許將 null 賦給值型別。
4.每種值型別均有一個隱式的預設建構函式來初始化該型別的預設值。
10、abstract class和interface有什麼區別?
相同點:
都不能被直接例項化,都可以通過繼承實現其抽象方法。
不同點:
介面支援多繼承;抽象類不能實現多繼承。
介面只能定義行為;抽象類既可以定義行為,還可能提供實現。
介面只包含方法(Method)、屬性(Property)、索引器(Index)、事件(Event)的簽名,但不能定義欄位和包含實現的方法;
抽象類可以定義欄位、屬性、包含有實現的方法。
介面可以作用於值型別(Struct)和引用型別(Class);抽象類只能作用於引用型別。例如,Struct就可以繼承介面,而不能繼承類。
加分的補充回答:講設計模式的時候SettingsProvider的例子。
11、ref與out的區別?
Ref的引數,要求傳遞進來的變數必須宣告,並且賦值
ref應用與內部對外部的值進行改變,out則是內部為外部變數賦值,out一般用在函式有多個返回值的場所。
Out引數,傳遞到out引數的變數,宣告不需要賦值(賦值也沒有意義),在out引數所在的方法中,out引數必須賦值,並且是在使用前賦值
12、堆和棧的區別?
棧是編譯期間就分配好的記憶體空間,因此你的程式碼中必須就棧的大小有明確的定義;區域性值型別變數、值型別引數等都在棧記憶體中。
堆是程式執行期間動態分配的記憶體空間,你可以根據程式的執行情況確定要分配的堆記憶體的大小。
13、XML 與 HTML 的主要區別
1. XML是區分大小寫字母的,HTML不區分。
2. 在HTML中,如果上下文清楚地顯示出段落或者列表鍵在何處結尾,那麼你可以省略</p>或者</li>之類的結束 標記。在XML中,絕對不能省略掉結束標記。
HTML:<img src="1.jpg"><br><br>
XML:<img src="1.jpg"></img><br/><br/>
3. 在XML中,擁有單個標記而沒有匹配的結束標記的元素必須用一個 / 字元作為結尾。這樣分析器就知道不用 查詢結束標記了。
4. 在XML中,屬性值必須分裝在引號中。在HTML中,引號是可用可不用的。
5. 在HTML中,可以擁有不帶值的屬性名。在XML中,所有的屬性都必須帶有相應的值。
XML是用來儲存和傳輸資料的
HTML是用來顯示資料的
如果使用了完全符合XML語法要求的HTML,那麼就叫做符合XHTML標準。符合XHTML標準的頁面有利於SEO。
14、string str = null 與 string str = “”說明其中的區別。
答:string str = null 是不給他分配記憶體空間,而string str = \"\" 給它分配長度為空字串的記憶體空間。 string str = null沒有string物件,string str = “”有一個字串物件。
string s3 = string.Empty;//反編譯發現,string.Empty就是在類建構函式中 Empty = "";
15、StringBuilder 和 String 的區別?
答:String 在進行運算時(如賦值、拼接等)會產生一個新的例項,而 StringBuilder 則不會。所以在大量字串拼接或頻繁對某一字串進行操作時最好使用 StringBuilder,不要使用 String
如果要操作一個不斷增長的字串,儘量不用String類,改用StringBuilder類。兩個類的工作原理不同:String類是一種傳統的修改字串的方式,它確實可以完成把一個字串新增到另一個字串上的工作沒錯,但是在.NET框架下,這個操作實在是划不來。因為系統先是把兩個字串寫入記憶體,接著刪除原來的String物件,然後建立一個String物件,並讀取記憶體中的資料賦給該物件。這一來二去的,耗了不少時間。而使用System.Text名稱空間下面的StringBuilder類就不是這樣了,它提供的Append方法,能夠在已有物件的原地進行字串的修改,簡單而且直接。當然,一般情況下覺察不到這二者效率的差異,但如果你要對某個字串進行大量的新增操作,那麼StringBuilder類所耗費的時間和String類簡直不是一個數量級的。
16、您在什麼情況下會用到虛方法?它與介面有什麼不同?
答案:子類重新定義父類的某一個方法時,必須把父類的方法定義為virtual
在定義介面中不能有方法體,虛方法可以。
實現時,子類可以不重新定義虛方法,但如果一個類繼承介面,那必須實現這個介面。
17、string、String;int、Int32;Boolean、bool的區別
String、Int32、Boolean等都屬於.Net中定義的類,而string、int、bool相當於C#中對這些類定義的別名。CTS。
18、.Net、ASP.Net、C#、VisualStudio之間的關係是什麼?
答:.Net一般指的是.Net Framework,提供了基礎的.Net類,這些類可以被任何一種.Net程式語言呼叫,.Net Framework還提供了CLR、JIT、GC等基礎功能。
ASP.Net是.Net中用來進行Web開發的一種技術,ASP.Net的頁面部分寫在aspx 檔案中,邏輯程式碼通常通過Code-behind的方式用C#、VB.Net等支援.Net的語言編寫。
C#是使用最廣泛的支援.Net的程式語言。除了C#還有VB.Net、IronPython等。
VisualStudio是微軟提供的用來進行.Net開發的整合開發環境(IDE),使用VisualStudio可以簡化很多工作,不用程式設計師直接呼叫csc.exe等命令列進行程式的編譯,而且VisualStudio提供了程式碼自動完成、程式碼高亮等功能方便開發。除了VisualStudio,還有SharpDevelop、MonoDevelop等免費、開源的IDE,VisualStudio Express版這個免費版本。
概念說明型
1、簡述 private、 protected、 public、 internal 修飾符的訪問許可權。
private : 私有成員, 在類的內部才可以訪問。
protected : 保護成員,該類內部和繼承類中可以訪問。
public : 公共成員,完全公開,沒有訪問限制。
internal: 當前程式集內可以訪問。
2:new有幾種用法
第一種:new Class();
第二種:覆蓋方法
public new XXXX(){}
第三種:new 約束指定泛型類宣告中的任何型別引數都必須有公共的無引數建構函式。
3、用sealed修飾的類有什麼特點
答 sealed 修飾符用於防止從所修飾的類派生出其它類。如果一個密封類被指定為其他類的基類,則會發生編譯時錯誤。密封類不能同時為抽象類。
sealed 修飾符主要用於防止非有意的派生,但是它還能促使某些執行時優化。具體說來,由於密封類永遠不會有任何派生類,所以對密封類的例項的虛擬函式成員的呼叫可以轉換為非虛擬呼叫來處理。String就是用sealed修飾的,所以不能被繼承。
4、請程式設計遍歷頁面上所有TextBox控制元件並給它賦值為string.Empty?
答:
foreach
(System.Windows.Forms.Control control in this.Controls)
{
if
(control is System.Windows.Forms.TextBox)
{
System.Windows.Forms.TextBox tb =
(System.Windows.Forms.TextBox)control ;
tb.Text = String.Empty ;
}
}
5、在.net中,配件的意思是?
答:程式集。(中間語言,源資料,資源,裝配清單)
6、C#中索引器是否只能根據數字進行索引?是否允許多個索引器引數?
引數的個數和型別都是任意的。加分的補充回答:用reflector反編譯可以看出,索引器的內部本質上就是set_item、get_item方法。
基礎知識:
索引的語法:
public string this[string s],通過get、set塊來定義取值、賦值的邏輯
索引可以有多個引數、引數型別任意
索引可以過載。
如果只有get沒有set就是隻讀的索引。
索引其實就是set_Item、get_Item兩個方法。
7.概述反射和序列化
反射:程式集包含模組,而模組包含型別,型別又包含成員。反射則提供了封裝程式集、模組和型別的物件。您可以使用反射動態地建立型別的例項,將型別繫結到現有物件,或從現有物件中獲取型別。然後,可以呼叫型別的方法或訪問其欄位和屬性
序列化:序列化是將物件轉換為容易傳輸的格式的過程。例如,可以序列化一個物件,然後使用 HTTP 通過 Internet 在客戶端和伺服器之間傳輸該物件。在另一端,反序列化將從該流重新構造物件。
8、關於拆箱裝箱:
1)什麼是裝箱(boxing)和拆箱(unboxing)? (*)
Object是引用型別,但是它的子類Int32竟然不能去Object能去的“要求必須是引用型別”
的地方,違反了繼承的原則,所以需要把Int32裝在Object中才能傳遞。
裝箱:從值型別介面轉換到引用型別。
拆箱:從引用型別轉換到值型別。
object obj = null;//引用型別
obj = 1;//裝箱,boxing。把值型別包裝為引用型別。
int i1 = (int)obj;//拆箱。unboxing
2)下面三句程式碼有沒有錯,以inboxing或者unboxing為例,解釋一下記憶體是怎麼變化的
int i=10;
object obj = i;
int j = obj;
分析:在inboxing(裝箱)時是不需要顯式的型別轉換的,不過unboxing(拆箱)需要顯式的型別轉換,所以第三行程式碼應該改為:
3 int j = (int)obj;
要掌握裝箱與拆箱,就必須瞭解CTS及它的特點:
NET重要技術和基礎之一的CTS(Common Type System)。CTS是為了實現在應用程式宣告和使用這些型別時必須遵循的規則而存在的通用型別系統。.Net將整個系統的型別分成兩大類 :值型別和引用型別。
CTS中的所有東西都是物件;所有的物件都源自一個基類——System.Object型別。值型別的一個最大的特點是它們不能為null,值型別的變數總有一個值。為了解決值型別不可以為null,引用型別可以為null的問題,微軟在.Net中引入了裝箱和拆箱:裝箱就是將值型別用引用型別包裝起來轉換為引用型別;而從引用型別中拿到被包裝的值型別資料進行拆箱。
object.ReferenceEquals();//用來判斷兩個物件是否是同一個物件
Console.WriteLine(object.ReferenceEquals(3,3));//因為兩個3被裝到了兩個箱子中,所以是false
Equals ==的關係
9、CTS、CLS、CLR分別作何解釋(*)把英文全稱背過來。
C#和.Net的關係。
C#只是抽象的語言,可以把C#編譯生成Java平臺的二進位制程式碼,也可以把Java程式碼編譯生成.Net平臺的二進位制程式碼。所以C#只是提供了if、while、+-*/、定義類、int、string等基礎的語法,而Convert.ToInt32、FileStream、SqlConnection、String.Split等都屬於.Net的東西。深藍色是C#的,淺藍色是.Net的。
C# new→IL:newobj
C# string →.Net中的String
型別的差別:.net中的Int32在C#中是int,在VB.Net中是Integer。
語法的差別:IL中建立一個物件的方法是L_0001: newobj instance void 索引.C1::.ctor()
C#中是new C1();VB.net中是 Dim c1 As New C1
CTS:Common Type System 通用型別系統。Int32、Int16→int、String→string、Boolean→bool。每種語言都定義了自己的型別,.Net通過CTS提供了公共的型別,然後翻譯生成對應的.Net型別。
CLS:Common Language Specification 通用語言規範。不同語言語法的不同。每種語言都有自己的語法,.Net通過CLS提供了公共的語法,然後不同語言翻譯生成對應的.Net語法。
CLR:Common Language Runtime 公共語言執行時,就是GC、JIT等這些。有不同的CLR,比如伺服器CLR、Linux CLR(Mono)、Silverlight CLR(CoreCLR)。相當於一個發動機,負責執行IL。
10、能用foreach遍歷訪問的物件的要求
需要實現IEnumerable介面或宣告GetEnumerator方法的型別。
11、GC是什麼? 為什麼要有GC?
C/C++中由程式設計師進行物件的回收像學校食堂中由學生收盤子,.Net中由GC進行垃圾回收像餐館中店員去回收。
GC是垃圾收集器(Garbage Collection)。程式設計師不用擔心記憶體管理,因為垃圾收集器會自動進行管理。GC只能處理託管記憶體資源的釋放,對於非託管資源則不能使用GC進行回收,必須由程式設計師手工回收,一個例子就是FileStream或者SqlConnection需要程式設計師呼叫Dispose進行資源的回收。GC不能回收非託管資源,對於非託管資源一般都實現了IDisposable介面,然後使用using關鍵字進行資源的回收。
要請求垃圾收集,可以呼叫下面的方法:GC.Collect()一般不需要手動呼叫GC.Collect()。當一個物件沒有任何變數指向(不再能使用)的時候就可以被回收了。
基礎知識:當沒有任何變數指向一個物件的時候物件就可以被回收掉了,但不一定會立即被回收。
object obj = new object();//只有new才會有新物件
Console.WriteLine(obj);
object obj2 = obj;
obj = null;
obj2 = null;
Console.WriteLine();
12、using關鍵字有什麼用?什麼是IDisposable?
using可以宣告namespace的引入,還可以實現非託管資源的釋放,實現了IDisposiable的類在using中建立,using結束後會自動呼叫該物件的Dispose方法,釋放資源。Idisosiable類含Close 、Dispose、finalize方法。加分的補充回答:using其實等價於try……finally,用起來更方便。
13、傳入某個屬性的set方法的隱含引數的名稱是什麼?
value,它的型別和屬性所聲名的型別相同。
14、說出一些常用的類、介面,請各舉5個
要讓人家感覺你對.Net開發很熟,所以,不能僅僅只列誰都能想到的那些東西,要多列你在做專案中涉及的那些東西。就寫你最近寫的那些程式中涉及的那些類。
常用的類:StreamReader、WebClient、Dictionary<K,V>、StringBuilder、SqlConnection、FileStream、File、Regex、List<T>
常用的介面:IDisposable、IEnumerable、IDbConnection、IComparable、ICollection、IList、IDictionary
要出乎意料!不要僅僅完成任務!筆試不是高考!處處要顯出牛!
是非型
1、不是說字串是不可變的嗎?string s="abc";s="123"不就是變了嗎?
String是不可變的在這段程式碼中,s原先指向一個String物件,內容是 "abc",然後我們將s指向"123",那麼s所指向的那個物件是否發生了改變呢?答案是沒有。這時,s不指向原來那個物件了,而指向了另一個 String物件,內容為"123",原來那個物件還存在於記憶體之中,只是s這個引用變數不再指向它了。
2、是否可以從一個static方法內部發出對非static方法的呼叫?
不可以。因為非static方法是要與物件關聯在一起的,必須建立一個物件後,才可以在該物件上進行方法呼叫,而static方法呼叫時不需要建立物件,可以直接呼叫。也就是說,當一個static方法被呼叫時,可能還沒有建立任何例項物件,如果從一個static方法中發出對非static方法的呼叫,那個非static方法是關聯到哪個物件上的呢?這個邏輯無法成立,所以,一個static方法內部不能發出對非static方法的呼叫。
3、C#支援多重繼承麼?
類之間不支援,介面之間支援。類對介面叫做實現,不叫繼承。 類是爹、介面是能力,能有多個能力,但不能有多個爹。
4、public static const; int A = 1;這段程式碼有錯誤麼?
錯誤:const不能被修飾為static ;因為定義為常量 (const )後就是靜態的(static )。
5、int、DateTime、string是否可以為null?
null表示“不知道”,而不是“沒有”。沒有年齡和不知道年齡是不一樣。
資料庫中null不能用0表示。0歲和不知道多少歲不一樣。
Sex is zero。《色即是空》
//int i1 = null;
//int? i2 = null;//值型別後加?就成了可空資料型別
////int i3 = i2;//所以把可空的賦值給一定不能為空的會報錯。
//int i4 = (int)i2;//可以顯式轉換,由程式設計師來保證“一定不為空”
//int? i5 = i4;//一定會成功!
//using()→try{]catch{}finally{}
//int?是微軟的一個語法糖。是一種和int沒有直接關係的Nullable型別
Nullable<int> d1 = new Nullable<int>();//int? d1=null;
Nullable<int> d2 = new Nullable<int>(3);//int? d2=3;
Console.WriteLine(d1==null);
int、DateTime不能,因為其為Struct型別,而結構屬於值型別,值型別不能為null,只有引用型別才能被賦值null。string可以為null。
C#中int等值型別不可以為null、而資料庫中的int可以為null,這就是糾結的地方。int?就變成了可空的int型別。bool?、DateTime?
int i1 = 3;
int? i2 = i1;
//int i3 = i2;//不能把可能為空的賦值給一定不能為空的變數
int i3 = (int)i2;//顯式轉換
可空資料型別經典應用場景:三層中的Model屬性的設計。
int?翻譯生成.Net的Nullable<int>,CTS。
6、能否脫離VS用類似editplus的工具手寫程式碼?你覺得如何才能提高程式碼的效率和效能?
可以,使用CSC.exe 來編譯.cs檔案!
可以根據業務流程、業務資料的特點進行優化,比如可以採用快取、索引、表驅動等來提升程式碼的效率和效能,同時不要進行無意義的程式碼優化,重點優化系統的效能瓶頸。
7、利用operator宣告且僅聲明瞭==,有什麼錯誤麼? 要同時修改Equale和GetHash() ? 過載了"==" 就必須過載 "!="
8、short s=1;s=s+1;有錯嗎?short s=1;s+=1;有錯嗎?
答案:第一個有錯,因為1是int型別,int+short結果是int,無法隱式轉換,改為s = (short)(s + 1);就可以了。
第二個沒錯,經過反編譯發現編譯器自動優化成s = (short)(s + 1);
程式碼分析型
1、
static void Main(string[] args)
{
Console.WriteLine(GetIt());
Console.ReadKey();
}
static int GetIt()
{
int i = 8;
try
{
i++;
Console.WriteLine("a");
return i;//把返回值設定為i,然後“儘快”返回(沒啥事就回去吧)
}
finally
{
Console.WriteLine("b");
i++;
}
}
上面程式的執行結果是ab9
try {}裡有一個return語句,那麼緊跟在這個try後的finally {}裡的程式碼會不會被執行,什麼時候被執行?
會執行,在return後執行。
static void Main(string[] args)
{
//Console.WriteLine(GetIt());
Console.WriteLine(GetPerson().Age);
Console.ReadKey();
}
static int GetIt()
{
int i = 8;
try
{
i++;
Console.WriteLine("a");
return i;//把返回值設定為i,然後“儘快”返回(沒啥事就回去吧。搞完就走)
}
finally
{
Console.WriteLine("b");
i++;
}
}
static Person GetPerson()
{
Person p = new Person();
p.Age = 8;
try
{
p.Age++;
Console.WriteLine("a");
return p;//把返回值設定為i,然後“儘快”返回(沒啥事就回去吧。搞完就走)
}
finally
{
Console.WriteLine("b");
p.Age++;
}
}
加分的補充回答(也助記):讀取資料庫中資料的條數的程式
public int QueryCount()
{
…..
try
{
return cmd.ExecuteScalar();
}
finally
{
cmd.Dispose();
}
}
先執行cmd.ExecuteScalar(),把返回值暫時存起來,然後再去執行finally(錢放在這,我去劫個色),然後把返回值返回。return都是最後執行,但是return後的表示式的計算則是在finally之前。
如果C#設計的是先執行cmd.Dispose()再執行return就會出現return執行失敗了,因為cmd已經Dispose了。
2、下面的程式執行結果是什麼?
class Person
{
public int Age { get; set; }
}
int i1 = 20;
int i2 = i1;
i1++;
Console.WriteLine(i2);
Person p1 = new Person();
p1.Age = 20;
Person p2 = p1;
p1.Age++;
Console.WriteLine(p2.Age);
答案:
20
21
解釋:引用型別和值型別的區別。
3、下面程式的執行結果是什麼?
int i = 10;
Console.WriteLine(i++);
Console.WriteLine(++i);
Console.WriteLine(i=20);
Console.WriteLine(i==20);
答案:
10
12
20
True
解答:前兩個參考第80題,i++表示式的值為i自增之前的值,所以列印10,執行完成後i變成11,執行++i的時候表示式的值為自增以後的值12。C#中賦值表示式的值為變數被賦值的值,因此最後一個就輸出i賦值後的值20
while((line=reader.ReadLine())!=null)
{
}
4、下面程式的執行結果是什麼?
public struct Point
{
public int x;
public int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
Point p1 = new Point(100, 100);
Point p2 = p1;
p1.x = 200;
Console.WriteLine("{0},{1}", p1.x, p2.x);
答案:
200,100
解答:結構體是複製傳遞的。
5、請程式設計遍歷WinForm頁面上所有TextBox控制元件並給它賦值為string.Empty?
答:
foreach (System.Windows.Forms.Control control in this.Controls)
{
if (control is System.Windows.Forms.TextBox)
{
System.Windows.Forms.TextBox tb = (System.Windows.Forms.TextBox)control ;
tb.Text = String.Empty ;
}
}
6、
int i=2000;
object o=i;
i=2001;
int j=(int)o;
Console.WriteLine("i={0},o={1},j={2}",i,o,j);
輸出的結果是:
7、一個數組:1,1,2,3,5,8,13,21...+m,求第30位數是多少?用遞迴實現;
寫遞迴要確定兩個:遞迴的終止條件;遞迴表示式。
解答:總結遞迴規律:F(n)=F(n-2)+F(n-1) Fibonacci數列
static int F(int n)
{
if (n == 1)
{
return 1;
}
if (n == 2)
{
return 1;
}
return F(n - 2) + F(n - 1);
}
非遞迴(有bug嗎?),遞迴演算法的缺點:測試大資料
int n = Convert.ToInt32(Console.ReadLine());
if(n<=0)
{Console.WRiteLine("必須大於0");return;}
if(n==1) //時刻注意邊界值!!!
{
Console.WriteLine("1");
return;
}
int[] data =new int[n];
data[0] = 1;
data[1] = 1;
for(int i=2;i<n;i++)
{
data[i] = data[i-1]+data[i-2];
}
Console.WriteLine(data[n-1]);
上面程式的時間複雜度為O(n),空間複雜度為O(n)
參考:
演算法複雜度:時間複雜度:演算法執行需要消耗的時間的數量級、空間複雜度:演算法執行需要消耗的記憶體的數量級。
消耗的時間或者記憶體隨著問題規模的擴大而成正比增加,就是O(n)。
消耗的時間或者記憶體隨著問題規模的擴大而不變,就是O(1)。
消耗的時間或者記憶體隨著問題規模的擴大而n*n增加,就是O(n*n)
演算法複雜度只考慮最差情況(從一個數組中找出第一個大於10的數,時間複雜度為O(n)),並且演算法複雜度忽略常量和低階。把陣列數一遍和數兩遍的時間複雜度都是O(n)。把長度為n的陣列數n/2遍的時間複雜度還是O(n*n)。
上課時把陣列前後顛倒的演算法的時間複雜度為O(n),空間複雜度為O(1)。
8、產生一個int陣列,長度為100,並向其中隨機插入1-100,並且不能重複。(要求使用兩種方法)
解答:Random類是一個偽隨機數演算法,原理:
r(n)=(sed+r(n-1))%100;
class MyRand
{
private int seed;
private int prevNumber = 10;
public MyRand(int seed)
{
this.seed = seed;
}
public int Next()
{
int newRand = (seed + prevNumber) % 100;
prevNumber = newRand;
return newRand;
}
}
生成的隨機數是依賴於上一個的,所以叫“隨機數序列”。,確定的種子產生確定的隨機數序列。
為了避免每次生成的隨機數序列都一樣,所以一般採用當前系統執行的毫秒數Environment.TickCount做種子。
這就明白為什麼
//for (int i = 0; i < 10; i++)
//{
// Random rand = new Random();
// Console.WriteLine(rand.Next(100));
//}
是錯的。
經過反編譯,Random類的無參建構函式最終也是呼叫有參的,傳遞的就是當前毫秒數
public Random() : this(Environment.TickCount)
這就驗證了
//for (int i = 0; i < 10; i++)
//{
// Random rand = new Random();
// Console.WriteLine(rand.Next(100));
//}
為什麼一樣,或者一半一樣,是因為在同一毫秒內。
做法1:
List<int> list = new List<int>();
Random rand = new Random();
while (list.Count < 100)
{
int number = rand.Next(1, 101);//>=1,<101
if (!list.Contains(number))//如果list中已經含有這個數,則不插入
{
list.Add(number);
}
}
foreach (int i in list)
{
Console.WriteLine(i);
}
做法2:
先把1-100這100個數按順序放入陣列arr,再重複100次下面的操作,生成兩個介於 >=0,<100 之間的隨機數m、n,顛倒arr[m]和arr[n]的數。
int[] arr = new int[100];
//把100個數順序放入
for (int i = 0; i < 100; i++)
{
arr[i] = i + 1;
}
Random rand = new Random();
for (int i = 0; i < 100; i++)
{
//隨機生成兩個位置
int m = rand.Next(0, 100);
int n = rand.Next(0, 100);
//顛倒兩個位置
int temp = arr[m];
arr[m] = arr[n];
arr[n] = temp;
}
效率比第一種高的多,這個只需要N次,而上一種至少需要N*N次
常規筆試題:計算陣列{1,1,2,3,5,8....}第30位的值。
解答:斐波那契數列。最前兩個數是1,之後每個數都是前兩個數的和。
f(n)=f(n-2)+f(n-1)
第一種解法:
static int Fib(int n)
{
//面試時要格外注意檢查引數的合法值
//拿個卷面分也是好的
if (n < 0)
{
throw new ArgumentException("n不能為負數");
}
//return Fib(n - 2) + Fib(n - 1);
if (n == 0 || n == 1)
{
return 1;//遞迴一定要有終止條件
}
else
{
return Fib(n - 2) + Fib(n - 1);
}
}
第二種解法
//效率非常高!
static int Fib2(int n)
{
if (n < 0)
{
throw new ArgumentException("n不能為負數");
}
if (n == 0)
{
return 1;
}
int[] nums = new int[n+1];//題目不清,我就假定他認為的30位從0開始
nums[0] = 1;
nums[1] = 1;
//從前往後一個個的加,最後一位就是計算結果
for (int i = 2; i <= n; i++)
{
nums[i] = nums[i - 2] + nums[i - 1];
}
return nums[n];
}
晨飛燕第一次
2、氣泡排序
for (int j = 0; j < nums.Length - 1; j++)
{
for (int i = 0; i < nums.Length - 1 -j; i++)
{
if (nums[i] > nums[i + 1])
{
int temp = nums[i];
nums[i] = nums[i + 1];
nums[i + 1] = temp;
}
}
}
For(int i = 0;i<nums.length-1; i ++)
{
For(int j= 0;j<nums.length-1-i;j++)
{
If(nums[j]>nums[j+1])
{
Int temp=nums[j];
Nums[i]=nums[j+1];
Nums[j+1]=temp;
}
}
}
如果只是呼叫集合的Sort方法,是不滿足人家要求的!一定要自己寫!
8、有一個10個數的陣列,計算其中不重複數字的個數。{3,5,9,8,10,5,3}
工程化的非最優解答:用HashSet
int[] values = { 3, 5, 9, 8, 10, 5, 3 };
HashSet<int> set = new HashSet<int>();
foreach (int i in values)
{
set.Add(i);
}
foreach (int i in set)
{
Console.WriteLine(i);
}
9、下面程式的執行結果是什麼?
class Program
{
static void Main(string[] args)
{
Person p1 = new Person();//1:00
Console.WriteLine(DateTime.Now);
Thread.Sleep(1000 * 10);
Console.WriteLine(DateTime.Now);
Console.WriteLine(p1.BirthDay);
//打印出來的是物件New出來的時間
//因為欄位是物件被new出來的時候初始化的
Console.ReadKey();
}
}
class Person
{
public DateTime BirthDay = DateTime.Now;
}
再難一點
class Person
{
public static int A = 30;
static Person()//靜態建構函式在static欄位初始化完成後執行
{//靜態建構函式只執行一次
A++;
}
public int B = A++;//欄位的初始化賦值程式碼只是在new一個物件的時候執行,而不是每次用欄位的時候都執行
}
程式的執行結果是什麼?
Person p1 = new Person();
Console.WriteLine(p1.B);
Console.WriteLine(Person.A);
Console.WriteLine(p1.B);
Console.WriteLine(Person.A);
Person p2 = new Person();
Console.WriteLine(p2.B);
Console.WriteLine(Person.A);
10、下面的程式碼中有什麼錯誤嗎?_ abstract override 是不可以一起修飾______
using System;
class A
{
public virtual void F(){
Console.WriteLine("A.F");
}
}
abstract class B:A
{
public abstract override void F();
}
11、當類T只聲明瞭私有例項建構函式時,則在T的程式文字外部,_不可以_(可以 or 不可以)從T派生出新的類,_不可以_(可以 or 不可以)直接建立T的任何例項。
12.下面這段程式碼有錯誤麼?case():不行 default;
switch (i){
case():
CaseZero();
break;
case 1:
CaseOne();
break;
case 2:
dufault;
CaseTwo();
break;
}
13.以下程式碼段中能否編譯通過?請給出理由。
try
{
}
catch(FileNotFoundException e1)
{
}
catch(Exception e2)
{
}
catch(IOException e3)
{
}
catch
{
}
在ioexception的時候出錯,因為上一個catch(exception)已經包含了超型別的所有異常
14.class Class1
{
private static int count = 0;
static Class1()
{
count++;
}
public Class1()
{
count++;
}
}
Class1 o1 = new Class1();
Class1 o2 = new Class1();
請問,o1.Count的值是多少?( 3 )
填空選擇題
1、在.Net中所有可序列化的類都被標記為__[serializable]___?
2、在.Net託管程式碼中我們不用擔心記憶體漏洞,這是因為有了_ gC __?
3、以下敘述正確的是: B C
A. 介面中可以有虛方法。B. 一個類可以實現多個介面。 C. 介面不能被例項化。 D. 介面中可以包含已實現的方法。
4、對於一個實現了IDisposable介面的類,以下哪些項可以執行與釋放或重置非託管資源相關的應用程式定義的任務?(多選)
( ABC)
A.Close B.Dispose C.Finalize
D.using E.Quit
5、在DOM中,裝載一個XML文件的方法(B)
a)save方法 b)load方法 c)loadXML方法 d)send方法
6、介面是一種引用型別,在介面中可以宣告(A),但不可以宣告公有的域或私有的成員變數。
a)方法、屬性、索引器和事件; b)方法、屬性資訊、屬性; c)索引器和欄位; d)事件和欄位;
7、Net Framework通過什麼與COM元件進行互動操作?(Interop)
A.Side By SideB.Web Service
C.InteropD.PInvoke
8、Net依賴以下哪項技術實現跨語言互用性?( C )
A.CLR B.CTS C.CLS D.CTT
9、面向物件的語言具有________性、_________性、________性
答:封裝、繼承、多型。
不要背,腦子中要有聯想。
10、介面是一種引用型別,在介面中可以宣告( a),但不可以宣告公有的域或私有的成員變數。
a) 方法、屬性、索引器和事件;
b) 索引器和欄位;
c) 事件和欄位;
解讀:介面中不能宣告欄位只能宣告方法,屬性、索引器和事件 最終都編譯生成方法。因為欄位屬於實現層面的東西,只有存取值的時候才會用到欄位,所以中介面中不能定義欄位。
12. 下列關於C#中索引器理解正確的是(c
)
a) 索引器的引數必須是兩個或兩個以上
b) 索引器的引數型別必須是整數型
c) 索引器沒有名字
d) 以上皆非
12、 下面關於XML的描述錯誤的是(d)。
a) XML提供一種描述結構化資料的方法;
b) XML 是一種簡單、與平臺無關並被廣泛採用的標準;
c) XML文件可承載各種資訊;
d) XML只是為了生成結構化文件;
13、以下的C#程式碼,試圖用來定義一個介面:
public interface IFile
{
int A;
int delFile()
{
A
= 3;
}
void disFile();
}
關於以上的程式碼,以下描述錯誤的是(d
)。
a) 以上的程式碼中存在的錯誤包括:不能在介面中定義變數,所以int A程式碼行將出現錯誤;
b) 以上的程式碼中存在的錯誤包括:介面方法delFile是不允許實現的,所以不能編寫具體的實現函式;
c) 程式碼void disFile();宣告無錯誤,介面可以沒有返回值;
d) 程式碼void disFile();應該編寫為void disFile(){};
14 不定項選擇:
(1) 以下敘述正確的是: B C
A. 介面中可以有虛方法。B. 一個類可以實現多個介面。 C. 介面不能被例項化。 D. 介面中可以包含已實現的方法。
(3).對於一個實現了IDisposable介面的類,以下哪些項可以執行與釋放或重置非託管資源相關的應用程式定義的任務?(多選) ( ABCD )
A.Close B.Dispose C.Finalize
D.using E.Quit
(4)以下關於ref和out的描述哪些項是正確的?(多選) ( ACD )
A.使用ref引數,傳遞到ref引數的引數必須最先初始化。
B.使用out引數,傳遞到out引數的引數必須最先初始化。
C.使用ref引數,必須將引數作為ref引數顯式傳遞到方法。
D.使用out引數,必須將引數作為out引數顯式傳遞到方法。
15、單項選擇:
(1)下列選項中,(C)是引用型別。
a)enum型別 b)struct型別 c)string型別 d)int型別
(3).下列描述錯誤的是(D)
a)類不可以多重繼承而介面可以;
b)抽象類自身可以定義成員而介面不可以;
c)抽象類和介面都不能被例項化;
d)一個類可以有多個基類和多個基介面;
16、宣告一個委託public
delegate int myCallBack(int x); 則用該委託產生的回撥方法的原型應該是(b
)。
a) void myCallBack(int x) ;
b) int receive(int num) ;
c) string receive(int x) ;
d) 不確定的;