當初學 C# 時是找個人大概問了一下資料類型和分支語句就開始做項目了。這兩天又全面的看了一下相關的基礎知識(學而時習之嘛),總結了25個問題:
1.靜态成員和非靜态成員的差別?
2.const 和 static readonly 差別?
3.extern 是什麼意思?
4.abstract 是什麼意思?
5.internal 修飾符起什麼作用?
6.sealed 修飾符是幹什麼的?
7.override 和 overload 的差別?
8.什麼是索引訓示器?
9.new 修飾符是起什麼作用?
10.this 關鍵字的含義?
11.可以使用抽象函數重寫基類中的虛函數嗎?
12.密封類可以有虛函數嗎?
13.什麼是屬性通路器?
14.abstract 可以和 virtual 一起使用嗎?可以和 override 一起使用嗎?
15.接口可以包含哪些成員?
16.類和結構的差別?
17.接口的多繼承會帶來哪些問題?
18.抽象類和接口的差別?
19.别名訓示符是什麼?
20.如何手工釋放資源?
21.P/Invoke是什麼?
22.StringBuilder 和 String 的差別?
23.explicit 和 implicit 的含義?
24.params 有什麼用?
25.什麼是反射?
以下是我做的一份參考答案(C# 語言範疇之内),如果有不準确、不全面的,歡迎各位朋友指正!
答:
靜态變量使用 static 修飾符進行聲明,在類被執行個體化時建立,通過類進行通路
不帶有 static 修飾符聲明的變量稱做非靜态變量,在對象被執行個體化時建立,通過對象進行通路
一個類的所有執行個體的同一靜态變量都是同一個值,同一個類的不同執行個體的同一非靜态變量可以是不同的值
靜态函數的實作裡不能使用非靜态成員,如非靜态變量、非靜态函數等
示例:
結果:
Class1's staticStr: Class
tmpObj1's notstaticStr: tmpObj1
tmpObj2's notstaticStr: tmpObj2
const
用 const 修飾符聲明的成員叫常量,是在編譯期初始化并嵌入到用戶端程式
static readonly
用 static readonly 修飾符聲明的成員依然是變量,隻不過具有和常量類似的使用方法:通過類進行通路、初始化後不可以修改。但與常量不同的是這種變量是在運作期初始化
測試類:
strConst : Const
strStaticReadonly : StaticReadonly
修改後的示例:
結果
strStaticReadonly : StaticReadonly Changed
extern 修飾符用于聲明由程式集外部實作的成員函數
經常用于系統API函數的調用(通過 DllImport )。注意,和DllImport一起使用時要加上 static 修飾符
也可以用于對于同一程式集不同版本元件的調用(用 extern 聲明别名)
不能與 abstract 修飾符同時使用
<a href="https://images.cnblogs.com/cnblogs_com/reonlyrun/WindowsLiveWriter/C_A3C7/Image01%5B12%5D.png"></a>
abstract 修飾符可以用于類、方法、屬性、事件和索引訓示器(indexer),表示其為抽象成員
abstract 不可以和 static 、virtual 一起使用
聲明為 abstract 成員可以不包括實作代碼,但隻要類中還有未實作的抽象成員(即抽象類),那麼它的對象就不能被執行個體化,通常用于強制繼承類必須實作某一成員
1234567
7
6
5
4
3
2
1
internal 修飾符可以用于類型或成員,使用該修飾符聲明的類型或成員隻能在同一程集内通路
接口的成員不能使用 internal 修飾符
值得注意的是,如果為 internal 成員加上了 protected 修飾符,這時的通路級别為 internal 或 protected。隻是看字面意思容易弄錯,許多人認為 internal protected 應該是“隻有同一個程式集中的子類可以通路”,但其實它表示“同一個程式集中的所有類,以及所有程式集中的子類都可以通路”
示例
Example05Lib 項目的 Class1
Example05Lib 項目的 Class2 類可以通路到 Class1 的 strInternal 成員,當然也可以通路到 strInternalProtected 成員,因為他們在同一個程式集裡
Example05 項目裡的 Class3 類無法通路到 Class1 的 strInternal 成員,因為它們不在同一個程式集裡。但卻可以通路到 strInternalProtected 成員,因為 Class3 是 Class1 的繼承類
Example05 項目的 Program 類既無法通路到 Class1 的 strInternal 成員,也無法通路到 strInternalProtected 成員,因為它們既不在同一個程式集裡也不存在繼承關系
<a href="https://images.cnblogs.com/cnblogs_com/reonlyrun/WindowsLiveWriter/C_A3C7/Image036.png"></a>
sealed 修飾符表示密封
用于類時,表示該類不能再被繼承,不能和 abstract 同時使用,因為這兩個修飾符在含義上互相排斥
用于方法和屬性時,表示該方法或屬性不能再被重寫,必須和 override 關鍵字一起使用,因為使用 sealed 修飾符的方法或屬性肯定是基類中相應的虛成員
通常用于實作第三方類庫時不想被用戶端繼承,或用于沒有必要再繼承的類以防止濫用繼承造成層次結構體系混亂
恰當的利用 sealed 修飾符也可以提高一定的運作效率,因為不用考慮繼承類會重寫該成員
類 B 在繼承類 A 時可以重寫兩個虛函數,如圖所示:
<a href="https://images.cnblogs.com/cnblogs_com/reonlyrun/WindowsLiveWriter/C_A3C7/Image045.png"></a>
由于類 B 中對 F 方法進行了密封, 類 C 在繼承類 B 時隻能重寫一個函數,如圖所示:
<a href="https://images.cnblogs.com/cnblogs_com/reonlyrun/WindowsLiveWriter/C_A3C7/Image057.png"></a>
控制台輸出結果,類 C 的方法 F 隻能是輸出 類B 中對該方法的實作:
A.F
A.G
B.F
B.G
C.G
override 表示重寫,用于繼承類對基類中虛成員的實作
overload 表示重載,用于同一個類中同名方法不同參數(包括類型不同或個數不同)的實作
BaseClass.F
DeriveClass.F
Add for Int: 3
Add for int: 3.3
實作索引訓示器(indexer)的類可以象數組那樣使用其執行個體後的對象,但與數組不同的是索引訓示器的參數類型不僅限于int
簡單來說,其本質就是一個含參數屬性
X: 0 , Y: 0
X: 1 , Y: 0.841470984807897
X: 2 , Y: 0.909297426825682
X: 3 , Y: 0.141120008059867
X: 4 , Y: -0.756802495307928
X: 5 , Y: -0.958924274663138
X: 6 , Y: -0.279415498198926
X: 7 , Y: 0.656986598718789
X: 8 , Y: 0.989358246623382
X: 9 , Y: 0.412118485241757
Today is cloudy!
Today is fine!
Today is thundershower!
new 修飾符與 new 操作符是兩個概念
new 修飾符用于聲明類或類的成員,表示隐藏了基類中同名的成員。而new 操作符用于執行個體化一個類型
new 修飾符隻能用于繼承類,一般用于彌補基類設計的不足
new 修飾符和 override 修飾符不可同時用在一個成員上,因為這兩個修飾符在含義上互相排斥
3.1415
3.1415926
this 是一個保留字,僅限于構造函數和方法成員中使用
在類的構造函數中出現表示對正在構造的對象本身的引用,在類的方法中出現表示對調用該方法的對象的引用,在結構的構造上函數中出現表示對正在構造的結構的引用,在結構的方法中出現表示對調用該方法的結果的引用
this 保留字不能用于靜态成員的實作裡,因為這時對象或結構并未執行個體化
在 C# 系統中,this 實際上是一個常量,是以不能使用 this++ 這樣的運算
this 保留字一般用于限定同名的隐藏成員、将對象本身做為參數、聲明索引通路器、判斷傳入參數的對象是否為本身
37.5 Celsius = 99.5 Fahrenheit
Have this.: 4375 MSEL
Don't have this.: 4406 MSEL
可以
需使用 new 修飾符顯式聲明,表示隐藏了基類中該函數的實作
或增加 override 修飾符,表示抽象重寫了基類中該函數的實作
示例:
可以,基類中的虛函數将隐式的轉化為非虛函數,但密封類本身不能再增加新的虛函數
屬性通路器(Property Accessor),包括 get 通路器和 set 通路器分别用于字段的讀寫操作
其設計目的主要是為了實作面向對象(OO)中的封裝思想。根據該思想,字段最好設為private,一個精巧的類最好不要直接把字段設為公有提供給客戶調用端直接通路
另外要注意屬性本身并不一定和字段相聯系
abstract 修飾符不可以和 static、virtual 修飾符一起使用
abstract 修飾符可以和 override 一起使用,參見第11點
接口可以包含屬性、方法、索引訓示器和事件,但不能包含常量、域、操作符、構造函數和析構函數,而且也不能包含任何靜态成員
類:
類是引用類型在堆上配置設定,類的執行個體進行指派隻是複制了引用,都指向同一段實際對象配置設定的記憶體
類有構造和析構函數
類可以繼承和被繼承
結構:
結構是值類型在棧上配置設定(雖然棧的通路速度比較堆要快,但棧的資源有限放),結構的指派将配置設定産生一個新的對象。
結構沒有構造函數,但可以添加。結構沒有析構函數
結構不可以繼承自另一個結構或被繼承,但和類一樣可以繼承自接口
根據以上比較,我們可以得出一些輕量級的對象最好使用結構,但資料量大或有複雜處理邏輯對象最好使用類。
如:Geoemtry(GIS 裡的一個概論,在 OGC 标準裡有定義) 最好使用類,而 Geometry 中點的成員最好使用結構
X: 1, Y: 2, Z: 3
X: 4, Y: 5, Z: 6
X: 7, Y: 8, Z: 9
C# 中的接口與類不同,可以使用多繼承,即一個子接口可以有多個父接口。但如果兩個父成員具有同名的成員,就産生了二義性(這也正是 C# 中類取消了多繼承的原因之一),這時在實作時最好使用顯式的聲明
Count property: 100
Count function: 10000
抽象類(abstract class)可以包含功能定義和實作,接口(interface)隻能包含功能定義
抽象類是從一系列相關對象中抽象出來的概念, 是以反映的是事物的内部共性;接口是為了滿足外部調用而定義的一個功能約定, 是以反映的是事物的外部特性
分析對象,提煉内部共性形成抽象類,用以表示對象本質,即“是什麼”
為外部提供調用或功能需要擴充時優先使用接口
通過别名訓示符我們可以為某個類型起一個别名
主要用于解決兩個命名空間内有同名類型的沖突或避免使用備援的命名空間
别名訓示符在所有命名空間最外層定義,作用域為整個單元檔案。如果定義在某個命名空間内,那麼它隻在直接隸屬的命名空間内起作用
Class1.cs:
Class2.cs:
主單元(Program.cs):
com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib01's Class1
com.nblogs.reonlyrun.CSharp25QExample.Example19.Lib02's Class1
.NET 平台在記憶體管理方面提供了GC(Garbage Collection),負責自動釋放托管資源和記憶體回收的工作。但在以下兩種情況需要我們手工進行資源釋放:一、由于它無法對非托管資源進行釋放,是以我們必須自己提供方法來釋放對象内配置設定的非托管資源,比如你在對象的實作代碼中使用了一個COM對象;二、你的類在運作是會産生大量執行個體(象 GIS 中的Geometry),必須自己手工釋放這些資源以提高程式的運作效率
最理想的辦法是通過實作一個接口顯式的提供給客戶調用端手工釋放對象,System 命名空間内有一個 IDisposable 接口,拿來做這事非常合适,省得我們自己再聲明一個接口了
在受控代碼與非受控代碼進行互動時會産生一個事務(transition) ,這通常發生在使用平台調用服務(Platform Invocation Services),即P/Invoke
如調用系統的 API 或與 COM 對象打交道,通過 System.Runtime.InteropServices 命名空間
雖然使用 Interop 非常友善,但據估計每次調用事務都要執行 10 到 40 條指令,算起來開銷也不少,是以我們要盡量少調用事務
如果非用不可,建議本着一次調用執行多個動作,而不是多次調用每次隻執行少量動作的原則
String 在進行運算時(如指派、拼接等)會産生一個新的執行個體,而 StringBuilder 則不會。是以在大量字元串拼接或頻繁對某一字元串進行操作時最好使用 StringBuilder,不要使用 String
另外,對于 String 我們不得不多說幾句:
1.它是引用類型,在堆上配置設定記憶體
2.運算時會産生一個新的執行個體
3.String 對象一旦生成不可改變(Immutable)
3.定義相等運算符(== 和 !=)是為了比較 String 對象(而不是引用)的值
String: 375 MSEL
StringBuilder: 16 MSEL
A
B
explicit 和 implicit 屬于轉換運算符,如用這兩者可以讓我們自定義的類型支援互相交換
explicti 表示顯式轉換,如從 A -> B 必須進行強制類型轉換(B = (B)A)
implicit 表示隐式轉換,如從 B -> A 隻需直接指派(A = B)
隐式轉換可以讓我們的代碼看上去更漂亮、更簡潔易懂,是以最好多使用 implicit 運算符。不過!如果對象本身在轉換時會損失一些資訊(如精度),那麼我們隻能使用 explicit 運算符,以便在編譯期就能警告客戶調用端
紫霞仙子:神仙變妖怪?偷偷下凡即可。。。
孫悟空:妖怪想當神仙?再去修煉五百年!
params 關鍵字在方法成員的參數清單中使用,為該方法提供了參數個數可變的能力
它在隻能出現一次并且不能在其後再有參數定義,之前可以
a
b
c
d
100
33.33
System.Double[]
反射,Reflection,通過它我們可以在運作時獲得各種資訊,如程式集、子產品、類型、字段、屬性、方法和事件
通過對類型動态執行個體化後,還可以對其執行操作
簡單來說就是用string可以在runtime為所欲為的東西,實際上就是一個.net framework内建的萬能工廠
一般用于插件式架構程式和設計模式的實作,當然反射是一種手段可以充分發揮其能量來完成你想做的任何事情(前面好象見過一位高人用反射調用一個官方類庫中未說明的函數。。。)
反射執行個體化對象并調用其方法,屬性和事件的反射調用略去
Name: Clark, Age: 0
Name: Clark Zheng, Age: 27
本文轉自鋼鋼部落格園部落格,原文連結:http://www.cnblogs.com/xugang/archive/2007/10/23/934319.html,如需轉載請自行聯系原作者