C# Notizen 2 理解C#類(lèi)型

一、類(lèi)型
C#是一種類(lèi)型安全的靜態(tài)語(yǔ)言。這要求創(chuàng)建任何變量時(shí),都必須將其數(shù)據(jù)類(lèi)型告知編譯器;編譯器將確保只能將兼容的數(shù)據(jù)類(lèi)型存儲(chǔ)到變量中。這有助于避免常見(jiàn)的編程錯(cuò)誤,讓?xiě)?yīng)用程序更穩(wěn)定、更安全。
類(lèi)型分為三大類(lèi):

  • 值類(lèi)型
  • 引用類(lèi)型
  • 類(lèi)型參數(shù)

ps:實(shí)際上還有第4種類(lèi)型—指針,但核心C#語(yǔ)言不支持。指針包含數(shù)據(jù)在內(nèi)存中的實(shí)際位置(地址);還可對(duì)指針執(zhí)行算術(shù)運(yùn)算,就像它們是數(shù)字一樣。雖然指針功能強(qiáng)大,但要正確、安全地使用它們也很難。

為提供指針的靈活性(這也會(huì)帶來(lái)危險(xiǎn)),C#允許您編寫(xiě)不安全的代碼,在這些代碼中可創(chuàng)建和操作指針。使用不安全的代碼和指針時(shí),務(wù)必認(rèn)識(shí)到垃圾收集器不會(huì)跟蹤指針,您必須負(fù)責(zé)分配和釋放內(nèi)存。從某種意義上說(shuō),這類(lèi)似于在C#程序中編寫(xiě)C語(yǔ)言代碼。

除顯式的不安全代碼塊外,C#不允許在其他地方使用指針,這可以完全避免一類(lèi)常見(jiàn)的錯(cuò)誤,讓C#更安全得多。

簡(jiǎn)單地說(shuō),值類(lèi)型是完全獨(dú)立的,它“按值”復(fù)制。這意味著值類(lèi)型變量包含其數(shù)據(jù),不會(huì)因?yàn)樘幚硪粋€(gè)變量而影響另一個(gè)變量。值類(lèi)型又分為結(jié)構(gòu)、枚舉類(lèi)型和可以為null的類(lèi)型。

引用類(lèi)型包含指向?qū)嶋H數(shù)據(jù)的引用,這意味著兩個(gè)變量可能指向同一個(gè)對(duì)象,而操作其中一個(gè)變量將影響另一個(gè)變量。引用類(lèi)型又分為類(lèi)、數(shù)組、接口和委托。

ps:同一類(lèi)型系統(tǒng)
雖然對(duì)類(lèi)型進(jìn)行了上述分類(lèi),但 C#有一個(gè)統(tǒng)一類(lèi)型系統(tǒng),使得可將任何非指針類(lèi)型值視為對(duì)象。這讓值類(lèi)型獲得了引用類(lèi)型的優(yōu)點(diǎn),而不會(huì)增加不必要的開(kāi)銷(xiāo);并可對(duì)任何值(包括預(yù)定義值類(lèi)型)調(diào)用對(duì)象方法。

二、預(yù)定義類(lèi)型
2.1 預(yù)定義類(lèi)型
C#預(yù)定義了一組類(lèi)型,這些類(lèi)型對(duì)應(yīng)于通用類(lèi)型系統(tǒng)中的類(lèi)型。

Paste_Image.png
Paste_Image.png

通過(guò)包括表示布爾值的類(lèi)型(取值為true或false),可避免混淆布爾變量和整數(shù)變量。這有助于消除多種常見(jiàn)的編程錯(cuò)誤,讓編寫(xiě)含義不言自明的代碼更容易。

ps:在C語(yǔ)言中,布爾值表示為整數(shù),并讓程序員去決定0表示true還是false。通常,C語(yǔ)言程序定義表示整數(shù)值0和1的名稱(chēng)常量,以幫助消除這種模糊性,但并沒(méi)有禁止使用整數(shù)表示布爾值。

  • 類(lèi)型decimal最少包含28個(gè)有效位,旨在避免金融計(jì)算的誤差。double類(lèi)型主要用于物理計(jì)算,以減少表示誤差。
  • object是其他所有引用類(lèi)型和值類(lèi)型的基類(lèi);string用于表示一系列Unicode字符,這種變量賦值后就不能修改,因此string變量是不可修改的。
  • 除無(wú)符號(hào)整數(shù)類(lèi)型和sbyte外,其他所有預(yù)定義類(lèi)型都符合CLS,但是使用這些
  • 類(lèi)型時(shí),只要不將其聲明為公有的,您的代碼就符合CLS。如果這些類(lèi)型的變量必須是公有的,那么可轉(zhuǎn)而使用相應(yīng)的符合CLS的類(lèi)型。
  • 對(duì)于sbyte,可使用符合CLS的類(lèi)型short代替。
  • 對(duì)于uint,通常使用符合CLS的類(lèi)型long代替;如果存儲(chǔ)的值小于2147483647.5,那么也可使用int代替。
  • 對(duì)于 ulong ,通??墒褂梅?CLS 的類(lèi)型 decimal 代替,如果存儲(chǔ)的值小于9223372036854775807.5,那么也可使用long代替
  • 對(duì)于ushort,通??墒褂梅螩LS的類(lèi)型int代替,如果存儲(chǔ)的值小于32767.5,那么也可使用short代替。
  • System.Object:所有的值類(lèi)型以及類(lèi)、數(shù)組和委托等引用類(lèi)型都是從 object 派生而來(lái)的。接口類(lèi)型可能是從其他接口類(lèi)型派生而來(lái)的,但可轉(zhuǎn)換為object。
  • 類(lèi)型參數(shù)實(shí)際上不是從任何類(lèi)型派生而來(lái)的,但可轉(zhuǎn)換為object。
  • 不安全的指針類(lèi)型既不是從object派生而來(lái)的,也不能轉(zhuǎn)換為object,因?yàn)樗鼈儾皇艹R?guī)C#類(lèi)型規(guī)則的管轄。
  • 這一切意味著C#中的所有非指針類(lèi)型都可轉(zhuǎn)換為object,但可能并不是從object派生而來(lái)的。
  • C#還有一些特殊的類(lèi)型,其中最常見(jiàn)的是void。void表示不知道類(lèi)型。dynamic類(lèi)型類(lèi)似于 object,主要的不同之處在于,對(duì)這種類(lèi)型執(zhí)行的所有操作都將在運(yùn)行階段(而不是編譯階段)解析。
  • 雖然void和dynamic都是類(lèi)型,但var是隱式類(lèi)型,讓編譯器根據(jù)賦給變量的數(shù)據(jù)確定變量的類(lèi)型。

ps:var并非Variant的縮寫(xiě)
最初引入 var類(lèi)型時(shí),很多人認(rèn)為它相當(dāng)于Visual Basic中的Variant類(lèi)型。Variant 變量可用于存儲(chǔ)其他任何數(shù)據(jù)類(lèi)型的值,因此不屬于強(qiáng)類(lèi)型;而var類(lèi)型仍是強(qiáng)類(lèi)型,因?yàn)樵诰幾g階段將用特定數(shù)據(jù)類(lèi)型替換它。盡管如此,過(guò)度使用var可能降低代碼的可讀性,因此應(yīng)慎用。

2.2 其他的常用類(lèi)型
除標(biāo)準(zhǔn)的預(yù)定義類(lèi)型外,.NET Framework還提供了用于表示其他常用值的類(lèi)型。不同于預(yù)定義類(lèi)型,這些類(lèi)型沒(méi)有C#別名,但對(duì)其可執(zhí)行的操作不受影響。

2.2.1 日期和時(shí)間
要處理日期和時(shí)間值,可使用結(jié)構(gòu)DateTime,它能夠創(chuàng)建表示日期和時(shí)間、僅日期或僅時(shí)間的變量。新建DateTime變量時(shí),最常見(jiàn)的方法有兩種:使用各種重載的構(gòu)造函數(shù)之一;使用4個(gè)靜態(tài)的分析方法之一—Parse、ParseExact、TryParse或TryParseExact。

DateTime的常用屬性

Paste_Image.png
Paste_Image.png

對(duì)日期或時(shí)間值進(jìn)行加減運(yùn)算時(shí),可使用相應(yīng)的實(shí)例方法,它們返回一個(gè)新的DateTime值,而不是修改原來(lái)的值。

DateTime常用的算術(shù)運(yùn)算方法:

Paste_Image.png

還可使用減法運(yùn)算符將兩個(gè)DateTime值相減,結(jié)果為一個(gè)TimeSpan實(shí)例。TimeSpan實(shí)例表示時(shí)間間隔,以天數(shù)、小時(shí)數(shù)、分鐘數(shù)、秒數(shù)和毫秒數(shù)表示,可正可負(fù)。為確保一致性,時(shí)間間隔以天數(shù)為單位。還可將DateTime與TimeSpan相加或相減,結(jié)果為一個(gè)新的DateTime實(shí)例。

TimeSpan常用的方法和屬性

Paste_Image.png
Paste_Image.png

2.2.2 全局唯一標(biāo)識(shí)符(GUID)
GUID是一個(gè)128位的整數(shù)值,重復(fù)的可能性很小,每當(dāng)需要唯一標(biāo)識(shí)符時(shí)就可以使用它。結(jié)構(gòu)System.Guid、能夠創(chuàng)建和比較GUID值
常用成員:

Paste_Image.png

2.2.3 統(tǒng)一資源標(biāo)識(shí)符(URI)
URI是內(nèi)聯(lián)網(wǎng)或Internet上可用資源的簡(jiǎn)潔表示,可以是絕對(duì)URI(如網(wǎng)頁(yè)地址),也可以是相對(duì)URI,后者必須根據(jù)基本URI進(jìn)行擴(kuò)展。
Uri類(lèi)讓您能夠新建URI以及訪(fǎng)問(wèn)URI的成員,它還提供了處理URI所需的方法,如分析、比較和合并。
常用成員:

Paste_Image.png

Uri實(shí)例是不能修改的。要?jiǎng)?chuàng)建可修改的URI,可使用UriBuilder。UriBuilder類(lèi)讓您能夠輕松地修改URI的屬性,而無(wú)需每次修改時(shí)都新建實(shí)例。
Uri和UriBuilder都有的屬性(在Uri中,這些屬性是只讀的):

Paste_Image.png

2.2.4 BigInteger
類(lèi)型 System.Numerics.BigInteger 表示任意大的整數(shù)值,從理論上說(shuō),沒(méi)有上限和下限。創(chuàng)建BigInteger實(shí)例后,可以像使用其他整數(shù)類(lèi)型一樣使用,可對(duì)其進(jìn)行基本的數(shù)學(xué)運(yùn)算和比較。
結(jié)構(gòu)BigInteger包含其他整數(shù)類(lèi)型的方法和Math類(lèi)的方法,還有專(zhuān)門(mén)針對(duì)BigInteger的成員。
這個(gè)結(jié)構(gòu)的常用成員:

Paste_Image.png
Paste_Image.png

2.3 運(yùn)算符
C#支持大量的運(yùn)算符,但是這里只介紹比較常用的運(yùn)算符。運(yùn)算符是一種特殊符號(hào),用于在表達(dá)式中指出要執(zhí)行哪種運(yùn)算。所有C#預(yù)定義類(lèi)型都支持運(yùn)算符,但是并非所有類(lèi)型支持的運(yùn)算符都相同。

按優(yōu)先級(jí)順序列出了所有的C#運(yùn)算符。在每個(gè)類(lèi)別中,運(yùn)算符的優(yōu)先級(jí)順序相同。

Paste_Image.png

2.3.1 算術(shù)運(yùn)算符和賦值運(yùn)算符
C#提供了支持標(biāo)準(zhǔn)數(shù)學(xué)運(yùn)算的運(yùn)算符:加法(+)、減法(?)、乘法(*)和除法(/)。根據(jù)相除的數(shù)據(jù)類(lèi)型的不同,除法的行為也稍有不同:將兩個(gè)整數(shù)相除時(shí),結(jié)果為整數(shù),并將余數(shù)丟棄。要獲得整數(shù)除法的余數(shù),必須使用求模運(yùn)算符%。

C#還支持復(fù)合賦值運(yùn)算符,這種運(yùn)算符將算術(shù)運(yùn)算和賦值合而為一。對(duì)于每個(gè)標(biāo)準(zhǔn)算術(shù)運(yùn)算符和求模運(yùn)算符,都有相應(yīng)的復(fù)合賦值運(yùn)算符,分別是+ =、? =、* =、/ =和% =,這些運(yùn)算符將賦值分別與加法、減法、乘法、除法和求模合而為一。

2.3.2 關(guān)系運(yùn)算符
關(guān)系運(yùn)算符用于比較兩個(gè)值,結(jié)果為布爾值。

Paste_Image.png

2.3.3 邏輯運(yùn)算符
邏輯運(yùn)算符用于布爾表達(dá)式中,結(jié)果為true或false。

Paste_Image.png
Paste_Image.png

邏輯運(yùn)算符的行為規(guī)則很容易總結(jié)。假設(shè)x和y都是布爾表達(dá)式,邏輯運(yùn)算的結(jié)果如下:

Paste_Image.png

2.3.4 條件運(yùn)算符
條件運(yùn)算符(也稱(chēng)為三目運(yùn)算符,因?yàn)樗婕?項(xiàng))對(duì)編寫(xiě)簡(jiǎn)潔表達(dá)式很有幫助,它對(duì)條件進(jìn)行評(píng)估,并根據(jù)結(jié)果返回兩個(gè)值之一。
條件運(yùn)算符的格式如下:
condition ? consequence : alternative
當(dāng)condition為true時(shí),將計(jì)算consequence并返回結(jié)果;如果condition為false,則計(jì)算alternative并返回結(jié)果。

ps:三目運(yùn)算符常見(jiàn)的問(wèn)題
這個(gè)運(yùn)算符是右結(jié)合的,這與其他大部分運(yùn)算符(左結(jié)合的)不同。這意味著對(duì)于下面的表達(dá)式相當(dāng)于 a ? b : ( c ? d : e ):
a ? b : c ? d : e
條件表達(dá)式的類(lèi)型是由consequence和alternative的類(lèi)型決定的,而不是它被賦給的變量決定的。
因此,consequence 和 alternative 的類(lèi)型必須相同,這意味著下面這樣的表達(dá)式無(wú)法通過(guò)編譯,因?yàn)槠鋍onsequence的類(lèi)型為int,而alternative的類(lèi)型為string:
object x = b ? 0 : "hello";
雖然上述代碼不實(shí)用,根本不應(yīng)在其他地方使用,但是其正確的書(shū)寫(xiě)方式可能如下:
object x = b ? (object)0 : (object)"hello";

2.4 默認(rèn)值
各種預(yù)定義數(shù)據(jù)類(lèi)型的默認(rèn)值:

Paste_Image.png

對(duì)于整型類(lèi)型,默認(rèn)值為零。char類(lèi)型的默認(rèn)值為空字符,而bool類(lèi)型的默認(rèn)值為false。類(lèi)型object和string的默認(rèn)值為null,即沒(méi)有指向任何對(duì)象。

2.5 null和可以為null的類(lèi)型
這些默認(rèn)值意味著值類(lèi)型不能為 null,看起來(lái)好像是合理的。然而,當(dāng)使用數(shù)據(jù)庫(kù)、其他外部數(shù)據(jù)源或其他可能沒(méi)有指定值的數(shù)據(jù)類(lèi)型時(shí),會(huì)帶來(lái)一定的限制。一個(gè)典型的示例就是數(shù)據(jù)庫(kù)中的數(shù)值字段,它可以存儲(chǔ)任何整型數(shù)據(jù),也可能沒(méi)有值。
對(duì)于這種問(wèn)題,可以為null的數(shù)據(jù)類(lèi)型提供解決方案??梢詾閚ull的類(lèi)型是這樣一種值類(lèi)型:可表示其底層類(lèi)型指定范圍內(nèi)的值以及null值??梢詾閚ull的類(lèi)型用語(yǔ)法Nullable<T>或T?表示,其中T是一種值類(lèi)型。語(yǔ)法T?使用更廣泛。給可以為null的類(lèi)型的變量賦值時(shí),方法與給其他變量賦值相同:
int = 10;
int? = 10;
int? = null;
要獲取可以為 null 的類(lèi)型的變量的值,應(yīng)使用方法 GetValueOrDefault,它返回賦給變量的值,如果沒(méi)有賦值,就返回底層類(lèi)型的默認(rèn)值。另外,還可以使用屬性 HasValue (如果給變量賦值了,該屬性將為true)和Value(它返回變量的實(shí)際值,如果值為null,就將引發(fā)異常)。
所有可以為 null 的類(lèi)型(包括引用類(lèi)型)都支持 null 合并運(yùn)算符(??)。將可以為 null的類(lèi)型的變量賦給不能為null的類(lèi)型的變量時(shí),可使用該運(yùn)算符指定要返回的默認(rèn)值。如果該運(yùn)算符左邊的操作數(shù)為 null,就返回右邊的操作數(shù);否則,返回左邊的操作數(shù)。程序清單2.4演示了如何使用null合并運(yùn)算符。

2.6 強(qiáng)制轉(zhuǎn)換與轉(zhuǎn)換
作為統(tǒng)一類(lèi)型系統(tǒng)的一部分,所有值類(lèi)型都可以轉(zhuǎn)換為 object。值類(lèi)型變量需要用作引用類(lèi)型時(shí),將自動(dòng)創(chuàng)建一個(gè)對(duì)象“箱”,并將值復(fù)制到箱子中。裝箱后,對(duì)一個(gè)變量的操作不會(huì)影響另一個(gè)。將對(duì)象箱變回到原來(lái)的值類(lèi)型時(shí),將把箱子內(nèi)的值復(fù)制到變量中。

ps:裝箱與取消裝箱
值類(lèi)型和引用類(lèi)型之間的轉(zhuǎn)換通常稱(chēng)為強(qiáng)制轉(zhuǎn)換(cast),因?yàn)檫@種轉(zhuǎn)換使用C# cast運(yùn)算符,但是相應(yīng)的CIL指令為 box和 unbox。
裝箱轉(zhuǎn)換總是隱式的,它將值類(lèi)型轉(zhuǎn)換為引用類(lèi)型。取消裝箱總是顯式的,它將裝箱的值類(lèi)型(引用類(lèi)型)轉(zhuǎn)換為值類(lèi)型。

裝箱和取消裝箱操作占用的資源很多,開(kāi)銷(xiāo)也很大,應(yīng)盡可能避免并確保使用正確的類(lèi)型來(lái)解決問(wèn)題。
如下是各種預(yù)定義類(lèi)型支持且能成功完成的隱式轉(zhuǎn)換。之所以允許這些隱式轉(zhuǎn)換,是因?yàn)閺脑紨?shù)值類(lèi)型轉(zhuǎn)換為新的數(shù)值類(lèi)型時(shí)不會(huì)降低量級(jí)。

Paste_Image.png

ps:隱式轉(zhuǎn)換
隱式轉(zhuǎn)換可能降低精度,但是不應(yīng)降低量級(jí)。以將 int 值轉(zhuǎn)換為 float值為例,它們都是32位的,但是并非每個(gè)int值都可以精確地表示為float,這將導(dǎo)致精度降低。然而,由于float的取值范圍比int大,因此這種轉(zhuǎn)換不會(huì)降低量級(jí)。
在轉(zhuǎn)換可能降低精度時(shí),必須進(jìn)行顯式轉(zhuǎn)換,此時(shí)需要指定要將原始值轉(zhuǎn)換為哪種類(lèi)型。顯式轉(zhuǎn)換的形式為(T) E,如圖所示,它將E的值轉(zhuǎn)換為類(lèi)型T。

Paste_Image.png

顯式轉(zhuǎn)換存在的問(wèn)題是,如果不小心,代碼就可能能夠編譯,但是運(yùn)行時(shí)會(huì)失敗。顯式轉(zhuǎn)換告訴編譯器,您定這種轉(zhuǎn)換能夠成功,如果不成功,導(dǎo)致的運(yùn)行階段錯(cuò)誤也是可以接受的。
為降低顯式轉(zhuǎn)換在運(yùn)行階段失敗的可能性,C#提供了 as運(yùn)算符,其形式為 e as T,其中e是一個(gè)表達(dá)式,而T必須是引用類(lèi)型或可以為null的類(lèi)型。as運(yùn)算符告訴編譯器,有充分的理由相信轉(zhuǎn)換將成功,它試圖將值轉(zhuǎn)換為類(lèi)型T并返回結(jié)果,如果轉(zhuǎn)換失敗,就返回null。
為利用as運(yùn)算符,可將上圖所示的代碼重寫(xiě)為如下形式:
int? i = 36;
object boxed = i;
int? j = boxed as int?;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,568評(píng)論 19 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線(xiàn)程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,706評(píng)論 18 399
  • 標(biāo)簽: 我的筆記 ---學(xué)習(xí)資料:http://javascript.ruanyifeng.com/ 1. 導(dǎo)論 ...
    暗夜的怒吼閱讀 950評(píng)論 0 1
  • 有多少一直不敢表白的人借著愚人節(jié)說(shuō)出那些情話(huà) 01 我喜歡你!嗯?嗯!啊哈,今天愚人節(jié)?對(duì)啊,哈哈,差點(diǎn)被騙了吧!...
    學(xué)長(zhǎng)talk閱讀 719評(píng)論 0 3
  • 這次嘗試使用代碼在LaTex中繪制樹(shù)狀圖,然而過(guò)程竟然頗為曲折。于是作此小記。 tikz 最初找到了這個(gè)包,于是使...
    Sicuso閱讀 2,124評(píng)論 1 0

友情鏈接更多精彩內(nèi)容