Object
支持 .NET 類層次結(jié)構(gòu)中的所有類,并為派生類提供低級別服務(wù)。 這是所有 .NET 類的最終基類;它是類型層次結(jié)構(gòu)的根。
簡單來說,它是萬能的,它是所有類型的父類。因?yàn)?NET 中的所有類都派生自 Object,因此 Object 類中定義的每個方法都可用于系統(tǒng)中的所有對象。
在 Object 類中提供了 4 個常用的方法,即 Equals、GetHashCode、GetType 以及 ToString 方法。
Equals
int a = 1;
int b = 1;
if (a.Equals(b))
{
Debug.Log("111"); -- 輸出111
}
Person a = new Person();
Person b = 1;
if (a.Equals(b))
{
Debug.Log("111"); -- 輸出111
}
Equals是相等判斷,與==相同,對于值類型的判斷是否值相同,而對于引用類型則判斷是否引用相同。
GetType
用于獲取當(dāng)前實(shí)例的類型,返回值為 System.Type 類型。GetType 方法不含任何參數(shù),是非靜態(tài)方法。
使用Object.GetType()來返回對象的類型x.GetType()和typeof()的區(qū)別是,GetType()是object的方法,可以用于所有變量后,以獲取它們的類型。和typeof(xxx)內(nèi)部只能放類型而不能放變量名。
ToString
將對象轉(zhuǎn)換為其字符串表示形式,使其適合顯示。
上述三種方法是可以重載,重寫的。
GetHashCode
返回對象的哈希值,每個對象的哈希值都是固定的。該方法不含有任何參數(shù),并且不是靜態(tài)方法,因此需要使用實(shí)例來調(diào)用該方法。由于該方法是在 Object 類中定義的,因此任何對象都可以直接調(diào)用該方法。
string
字符串類型string
表示零個或多個 Unicode 字符的序列。 比較特殊的是,盡管string是引用類型,但是使用==
來比較時卻是值類型的比較。需要注意的是,string是不可變類型,這意味著每次我們修改字符串string的操作實(shí)際上都是創(chuàng)建了一個新的字符串。
逐字文本
使用@
關(guān)鍵字標(biāo)識該字符串為逐字文本,將不會識別轉(zhuǎn)義符
@"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.
@"c:\Docs\Source\a.txt" // rather than "c:\\Docs\\Source\\a.txt"
復(fù)合格式字符串
使用String.Format方法將變量復(fù)合到格式項(xiàng)內(nèi),其中括號內(nèi)的數(shù)字代表了對應(yīng)的變量索引,而:
后面代表變量的指定類型。
String.Format("Name = {0}, hours = {1:hh}", name, DateTime.Now);
多個相同索引也可以同時存在
string multiple = String.Format("0x{0:X} {0:E} {0:N}",
Int64.MaxValue);
Console.WriteLine(multiple);
// The example displays the following output:
// 0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00
字符串內(nèi)插
使用$
關(guān)鍵字標(biāo)識字符串內(nèi)插
string name = "Mark";
var date = DateTime.Now;
// Composite formatting:
Console.WriteLine("Hello, {0}! Today is {1}, it's {2:HH:mm} now.", name, date.DayOfWeek, date);
// String interpolation:
Console.WriteLine($"Hello, {name}! Today is {date.DayOfWeek}, it's {date:HH:mm} now.");
(更多用法請閱讀官方文檔,尤其是string類的方法,尷尬的是string類的方法特別多,但是String大多數(shù)情況下卻被StringBuilder完爆)
StringBuilder
使用命名空間System.Text來引入該類型
StringBuilder可以說是String的完全上位替代,這是一個可變的字符串類。 可變性意味著,創(chuàng)建類的實(shí)例后,可以通過追加、刪除、替換或插入字符對其進(jìn)行修改。由于String每次修改時都需要產(chǎn)生一個新的字符串,這也就導(dǎo)致了對其進(jìn)行操作可能產(chǎn)生的一些內(nèi)存消耗問題。所以對于需要操作的字符串,我們會選擇StringBuilder,不過性能取決于字符串的大小、要為新字符串分配的內(nèi)存量、執(zhí)行代碼的系統(tǒng)以及操作的類型。
請考慮在以下情況下使用 String 類:
- 當(dāng)代碼對字符串進(jìn)行的更改數(shù)較小時。 在這些情況下, StringBuilder 可能會提供微不足道的性能改進(jìn),因此可以直接使用String。
- 執(zhí)行固定數(shù)量的串聯(lián)操作時,尤其是字符串文本。 在這種情況下,編譯器可能會將串聯(lián)操作合并到單個操作中。
- 在生成字符串時必須執(zhí)行廣泛的搜索操作時。 類 StringBuilder 缺少搜索方法,例如 IndexOf 或 StartsWith。 對于這些操作,必須將 StringBuilder對象轉(zhuǎn)換為String , 這可以抵消使用 StringBuilder的性能優(yōu)勢。 有關(guān)詳細(xì)信息,請參閱 在 StringBuilder 對象中搜索文本 部分。
請考慮在以下情況下使用 StringBuilder 類:
- 如果預(yù)期代碼在設(shè)計(jì)時對字符串進(jìn)行未知數(shù)量的更改, 例如,使用循環(huán)連接包含用戶輸入的隨機(jī)數(shù)量的字符串時。
- 預(yù)期代碼對字符串進(jìn)行大量更改時。
總的來說,一些短平快的操作,或者需要涉及串聯(lián)字符串,或是查詢整個字符串的時候更適合String。如果一些需要頻繁更改,或者動態(tài)修改的字符串更適合StringBuilder
StringBuilder 的工作原理
StringBuilder是如何動態(tài)修改字符串長度的?假設(shè)有一個字符串長度為12的stringBuilder,如果我們需要Append成一個length =20的字符串,那么首先StringBuilder會把字符串丟入這個長度為16的緩沖區(qū),當(dāng)長度超過緩沖區(qū)的長度時,則意味著需要更大的緩沖區(qū),則StringBuilder會找一個緩沖區(qū)大小翻一倍的新緩沖區(qū)(現(xiàn)在是32了)。然后把舊緩沖區(qū)的值復(fù)制過去,并加入那些超過原長度而未被存入舊緩沖區(qū)的新字符。如果還是超過就重復(fù)上述過程,直到存儲完畢為止。(如果超出了設(shè)定最大容量或者內(nèi)存沒有多余空間了則報錯)
public class Example
{
public static void Main()
{
StringBuilder sb = new StringBuilder();
ShowSBInfo(sb);
sb.Append("This is a sentence.");
ShowSBInfo(sb);
for (int ctr = 0; ctr <= 10; ctr++) {
sb.Append("This is an additional sentence.");
ShowSBInfo(sb);
}
}
private static void ShowSBInfo(StringBuilder sb)
{
foreach (var prop in sb.GetType().GetProperties()) {
if (prop.GetIndexParameters().Length == 0)
Console.Write("{0}: {1:N0} ", prop.Name, prop.GetValue(sb));
}
Console.WriteLine();
}
}
// The example displays the following output:
// Capacity: 16 MaxCapacity: 2,147,483,647 Length: 0
// Capacity: 32 MaxCapacity: 2,147,483,647 Length: 19
// Capacity: 64 MaxCapacity: 2,147,483,647 Length: 50
// Capacity: 128 MaxCapacity: 2,147,483,647 Length: 81
// Capacity: 128 MaxCapacity: 2,147,483,647 Length: 112
// Capacity: 256 MaxCapacity: 2,147,483,647 Length: 143
// Capacity: 256 MaxCapacity: 2,147,483,647 Length: 174
// Capacity: 256 MaxCapacity: 2,147,483,647 Length: 205
// Capacity: 256 MaxCapacity: 2,147,483,647 Length: 236
// Capacity: 512 MaxCapacity: 2,147,483,647 Length: 267
// Capacity: 512 MaxCapacity: 2,147,483,647 Length: 298
// Capacity: 512 MaxCapacity: 2,147,483,647 Length: 329
// Capacity: 512 MaxCapacity: 2,147,483,647 Length: 360
StringBuilder提供的方法
可以進(jìn)行單獨(dú)的方法調(diào)用并忽略返回值,如以下示例所示。
using System;
using System.Text;
public class Example
{
public static void Main()
{
StringBuilder sb = new StringBuilder();
sb.Append("This is the beginning of a sentence, ");
sb.Replace("the beginning of ", ""); //替換所有字符A為字符B
sb.Insert(sb.ToString().IndexOf("a ") + 2, "complete ");
sb.Replace(",", ".");
Console.WriteLine(sb.ToString()); //只有在必須接受string類型時再轉(zhuǎn)化為string
}
}
// The example displays the following output:
// This is a complete sentence.
可以在單個語句中調(diào)用一系列方法。 如果要編寫鏈接連續(xù)操作的單個語句,這可以很方便。 以下示例將上一示例中的三個方法調(diào)用合并到一行代碼中。
using System;
using System.Text;
public class Example
{
public static void Main()
{
StringBuilder sb = new StringBuilder("This is the beginning of a sentence, ");
sb.Replace("the beginning of ", "").Insert(sb.ToString().IndexOf("a ") + 2,
"complete ").Replace(",", ".");
Console.WriteLine(sb.ToString());
}
}
// The example displays the following output:
// This is a complete sentence.
訪問字符
訪問字符在我看來是StringBuilder的一大痛點(diǎn)。StringBuilder沒有提供訪問其內(nèi)部字符的方法,而想要訪問其中的某個字符卻沒那么簡單,因?yàn)榫彌_區(qū)的內(nèi)存是不連續(xù)的,如果想要找到某個字符,我們就需要遍歷整個緩沖區(qū)。因此較好的方法是通過ToString
方法將其轉(zhuǎn)化為String
類型之后使用char[Index]
去訪問對應(yīng)字符。
迭代字符
當(dāng)?shù)鶶tringBuilder的字符的時候,應(yīng)當(dāng)注意:即使對于大型“區(qū)塊” StringBuilder 對象,使用 Chars[] 屬性進(jìn)行基于索引的訪問一個或少量字符的性能影響可以忽略不計(jì);通常,這是 一個 O (n) 操作。 當(dāng)?shù)?StringBuilder 對象中的字符時,會對性能造成顯著的影響,這是 O(n^2) (遍歷n個字符*緩存區(qū)容量n)操作。
因此當(dāng)我們需要迭代StringBuilder的字符時,較好的方法還是通過ToString
方法將其轉(zhuǎn)化為String
類型之后使用char[Index]
去訪問對應(yīng)字符。
查詢字符
在StringBuilder中并沒有提供查詢字符的方法,想實(shí)現(xiàn)查詢字符,也只能轉(zhuǎn)為String
,然后用String.IndexOf
或者String.StartWith
方法查找對應(yīng)的字符或字符串。
由于String和StringBuilder提供的方法太多,因此此處無法深入,推薦閱讀官方文檔
dynamic
最后稍微了解一下dynamic動態(tài)類型。dynamic本身也是一個Object。在大多數(shù)情況下,dynamic 類型與 object 類型的行為類似。 具體而言,任何非 Null 表達(dá)式都可以轉(zhuǎn)換為 dynamic 類型。 dynamic 類型與 object 的不同之處在于,編譯器不會對包含類型 dynamic 的表達(dá)式的操作進(jìn)行解析或類型檢查。 編譯器將有關(guān)該操作信息打包在一起,之后這些信息會用于在運(yùn)行時評估操作。 在此過程中,dynamic 類型的變量會編譯為 object 類型的變量。 因此,dynamic 類型只在編譯時存在,在運(yùn)行時則不存在。
dynamic的特殊就在于它是不會在編譯時被解析的,因此不會進(jìn)行任何的安全檢查。因此即使定義了錯誤的dynamic,編譯器也不會報錯。而只有在運(yùn)行時出現(xiàn)錯誤才會報錯。
其次,由于dynamic的本質(zhì)是Object,它也可以和任何類型進(jìn)行隱式轉(zhuǎn)換。而這也是它的最大優(yōu)點(diǎn)。例如:
dynamic x = 10; //此時x為int
x = x + "Hello"; // x 現(xiàn)在是一個字符串
x = x.ToUpper(); // x 仍然是一個字符串
x = 8; // x 現(xiàn)在保存的是一個int類型的變量
x = x * 8; // x現(xiàn)在仍然是int
在上例中,我們定義x為dynamic,可以看出來它對應(yīng)應(yīng)當(dāng)是int型,然后我們將其轉(zhuǎn)化為字符串,然后對字符串進(jìn)行操作。隨后又把x賦值為了int類型的。x在整個程序中動態(tài)的變動它的類型。而這是var做不到的,因?yàn)関ar關(guān)鍵字下編譯器會自動地推斷它的類型,那它就是一個靜態(tài)類,一般沒有顯示轉(zhuǎn)換的前提下我們是不能進(jìn)行類型轉(zhuǎn)換的。
如果只用靜態(tài)類想實(shí)現(xiàn)則需要新創(chuàng)建其中設(shè)計(jì)到的靜態(tài)類型對應(yīng)的變量,而如果想讓靜態(tài)類型變量x實(shí)現(xiàn)上述過程只會更加復(fù)雜:文章來源:http://www.zghlxwxcb.cn/news/detail-624487.html
int x=10;
String y = x.ToString();
y=y+"Hello";
y = y.ToUpper();
x = 8;
x = x* 8
而dynamic的動態(tài)類型實(shí)際和某些腳本語言的變量性質(zhì)是非常相似的。因此我們也使用dynamic類型來與腳本語言進(jìn)行對接。文章來源地址http://www.zghlxwxcb.cn/news/detail-624487.html
到了這里,關(guān)于【C#學(xué)習(xí)筆記】引用類型(2)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!