?目錄
本文分兩篇,進階篇點擊:C#基礎與進階擴展合集-進階篇
一、基礎入門
Ⅰ 關鍵字
Ⅱ 特性
Ⅲ 常見異常
Ⅳ 基礎擴展
1、哈希表?
2、擴展方法
3、自定義集合與索引器
4、迭代器與分部類
5、yield return
6、注冊表
7、不安全代碼
8、方法描述?
二、擴展類型
1、BigInteger
2、Half
3、Decimal
4、可空值類型
5、可空引用類型
6、空合并
7、轉義字符
8、StringBuilder
9、FormattableString?
10、元組?
三、其它
1、名稱空間取別名
2、字符串前$與@
3、預處理器指令
4、隱藏方法
5、顯示和隱式實現接口
6、泛型約束
7、字典初始化方式
8、集Set
9、有序集合
10、只讀字段與屬性?
本文分兩篇,進階篇點擊:C#基礎與進階擴展合集-進階篇
一、基礎入門
Ⅰ 關鍵字
1、record?
record(記錄),編譯器會在后臺創建一個類。支持類似于結構的值定義,但被實現為一個類,方便創建不可變類型,成員在初始化后不能再被改變?(C#9新增)
在運行時通過構造函數給成員賦值
2、init?
?init關鍵字,代替set(C#9新增)
特性:只能通過構造函數和對象初始化器來設置屬性值
public string Name { get; init; }
若用舊的.NET框架版本使用.NET 5代碼,需手動添加虛擬類,如下:
namespace System.Runtime.CompilerServices
{?
? ? internal static class IsExternalInit { }
}
3、with?
?with關鍵字(C#9新增),內部調用<>Clone淺copy方法,使用如下:
?MyMath myMath2=myMath1 with { };//淺拷貝
4、base?
base關鍵字,
作用1:子類實例化時默認調用父類的無參構造函數,base可指定調用父類對應的有參構造函數;
作用2:在子類中通過base調用父類被子類重寫的虛方法;
5、params
params,修飾方法參數,
1、被修飾的參數必須為一維數組
2、被修飾參數為最后參數,后面不允許有其它參數
6、ref、out、in
1、被ref或out或in修飾的參數通過引用方式傳遞;
2、傳參時也必須帶關鍵字ref(out、in);
3、ref修飾的參數傳參時必須提前定義并初始化,out可在傳參時定義;
4、out修飾的參數必須在控制離開方法之前對該參數賦值;
5、in修飾的值類型參數,方法內為只讀變量(可避免復制值的開銷);
7、sealed
sealed,有封裝的意思,一般用于修飾類或方法
1、修飾類時,該類不可被繼承;
2、修飾方法時,一般用于virtual與抽象方法的繼承類,sealed一般與override同時存在,被修飾的已重寫的方法不可被其派生類重寫。
8、lock
?lock, 確保代碼正常執行,不會被其他線程中斷;將代碼定義為互斥段,同一時刻只能由一個線程執行,其他線程必須等待(解決多線程同時搶占同一資源產生的沖突問題)
示例如下:
????????_root:指需要跟蹤的對象(通常實例化一個object作為跟蹤對象)
????????{? ?_list.Clear();? ?}:指定義為互斥段的代碼塊;?
lock(_obj){Count--;}
9、readonly
readonly,用于修飾字段為只讀字段?:
1、在運行時可通過構造函數賦值;
10、checked、unchecked
????????1、如果將一個代碼塊標記為checked,CLR就會對該代碼塊執行溢出檢查,溢出會拋出OverflowException異常,也可在表達式中使用checked關鍵字;
? ? ? ? 2、也可在配置項目文件中添加CheckForOverflowUnderflow設置,可對所有未標記的代碼進行溢出檢查,如:<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>,可使用unchecked關鍵字來標記不進行溢出檢查;
checked
{byte a = 255;a = (byte)(a + 3);
}
11、throw
拋出一個異常
throw new Exception("my exception...");
Ⅱ 特性
特性,指C#中對類及程序集成員的進一步描述
? ? ? ? 更多了解點擊:C#進階-特性? ?常用如下:
- ?[Key],指示該屬性為主鍵(僅對屬性、字段、索引器有效);
- ?[StringLength(maximumLength:50,MinimumLength =2)],限制字符串長度(僅對屬性、字段、參數、索引器有效);
- ?[EmailAddress],識別郵箱格式(僅對屬性、字段、參數、索引器有效);
- ?[Required],不可為空(僅對屬性、字段、參數、索引器有效);
- ?[Display(Name="電話號碼")],顯示別名;
- [CallerMemberName],獲取調用該方法的成員名(僅對參數有效);
- [CallerFilePath],獲取調用該方法的文件路徑(僅對參數有效);
- [CallerLineNumber],獲取調用該方法的行數(僅對參數有效);
- [Compare(“Password”, ErrorMessage = “”)],比較兩個屬性的值是否相同;
- [DataType(DataType.Password)],標記某屬性為密碼類型;
Ⅲ 常見異常
- ArgumentException,方法接受實參時,檢查實參未包含期望的值拋出,其派生有ArgumentNullException(空異常)和ArgumentOutOfRangeException(索引超出范圍);
- NotSupportedException,當不支持一個方法時拋出;
- StackOverflowException,當為棧分配的內存滿了導致溢出時拋出;
- OverflowException,在checked(關鍵字中有介紹)上下文中執行算術運算,當得到的值超出變量類型的取值范圍時拋出;
- IOException基類,文件I/O導致的異常,其派生有FileLoadException、FileNotFoundException、EndOfStreamException、DriveNotFoundException。。。
- InvalidOperationException,當沒有按正確順序調用類的方法(如缺少初始化調用)時拋出;
- TaskCanceledException,當任務取消或超時的時候拋出;
- NullReferenceException,當使用的?
null
?引用導致需要引用的對象時拋出;
?更多異常詳解:微軟文檔Exception-C#
Ⅳ 基礎擴展
1、哈希表?
了解哈希表:C#-關于Hashtable?
2、擴展方法
擴展方法詳解:C#-擴展方法定義及其使用
3、自定義集合與索引器
?自定義集合與索引器詳解:C#-自定義集合與索引器
4、迭代器與分部類
迭代器與分部類詳解:C#-關于迭代器與分部類?
5、yield return
yield示例詳解:C#-yield return實現數據迭代?
6、注冊表
了解注冊表相關操作:C#-注冊表的讀取、創建、修改、刪除操作
7、不安全代碼
了解指針(不安全代碼):?C#-關于指針使用(不安全代碼)
8、方法描述?
對自定義方法添加描述:C#-方法的功能、參數、返回值描述?
二、擴展類型
1、BigInteger
如果需要的數字比64位的long類型能夠表示的值更大,則可使用BigInteger類型,該類型無關鍵字,無位數限制,可以一直增長下去,直到沒有可用內存。
BigInteger bigInteger =111111111111111111;
2、Half
.NET5新增,16位單精度浮點數,無關鍵字,其有效位數為10位,指數位為5位;
注意:硬編碼的一個非整數值(1.92171),一般默認為double類型,需強轉;
Half half = (Half)1.92171;
3、Decimal
關鍵字decimal,.NET高精度浮點類型,128位,1位符號位、96位用作整數,剩下的位指定了比例因子。
注意:要把數字指定為該類型,在其數字后面加上字符M(或m);
decimal deci = 11111.11M;
4、可空值類型
①在類型定義中使用“?”,這將允許賦值null,如:int? a = null;
②編譯器會將該語句變成Nullable<T>類型,如:Nullable<int> a=null;
③Nullable<T>不會增加引用類型的開銷,仍然是struct值類型,只不過添加了一個布爾標志,用來指定值是否為null;
④總是可把不可為空的值賦值給可空值類型;
5、可空引用類型
①主要為了減少NullReferenceException類型的異常,可啟用可空引用類型獲得編譯器的幫助:1、在項目文件中指定Nullable將其設為enable,如:<Nullable>enable</Nullable>;
? ? ? ? 2、使用預處理器指令啟用:#nullable enable,禁用:#nullable disable,恢復項目文件中設置:#nullable restore
②啟用后給引用類型賦值(string c = null;)編譯器會報警告,若要賦值null,需加上“?”,如:string??c = null;
6、空合并
?string? s=null;
string s2 = s?.ToLower()??string.Format("");//使用null條件運算符和空合并運算符
Console.WriteLine($@"\t{s2}\t{{}}");
7、轉義字符
轉義序列 | 字符 |
---|---|
\' | 單引號 |
\" | 雙引號 |
\\ | 反斜杠 |
\0 | 空 |
\a | 警告 |
\b | 退格 |
\f | 換頁 |
\n | 換行 |
\r | 回車 |
\t | 水平制表符 |
\v | 垂直制表符 |
8、StringBuilder
StringBuilder sb = new StringBuilder("111111");//動態字符串默認容量16字符,成倍增加
sb.Append("abcdefghjklmnopq");
Console.WriteLine(sb.Length);//獲取有效長度
Console.WriteLine(sb.Capacity);//獲取容量
9、FormattableString?
?FormattableString str = $"time:{t},number:{a}";//格式化字符串類型
Console.WriteLine("格式str:{0}",str.Format);//獲取格式化字符串的原始字符串
for (int i = 0; i < str.ArgumentCount; i++)
{
? ? Console.WriteLine("Arg{0}:{1}", i, str.GetArgument(i));//獲取參數值
}
10、元組?
?元組,把多個類型合為一個類型,不需要創建類、結構、記錄
? ? ? ? ? ? var t=(String:"sss",Int32: 32);
? ? ? ? ? ? t.Int32 = 2;
? ? ? ? ? ? t.String = "Auston";.Net提供了Tuple<T>舊類型
? ? ? ? ? ? ? ? ? ValueTuple<T>新類型(推薦)有更好的內置支持
三、其它
1、名稱空間取別名
主要用于解決名稱空間二義性問題:?
using Sys = System;Sys.Console.WriteLine("Hello, Auston!");
2、字符串前$與@
字符串插值:字符串前帶$前綴,允許在字符串類計算表達式;
verbatim字符串:字符串前帶@前綴,解決反斜杠轉義問題,常用于文件路徑;
string a = "hello";
Console.WriteLine($"a:{a}");
Console.WriteLine(@"\file\a.txt");
3、預處理器指令
- #define,定義符號;
- #undef,刪除符號定義;
- #if、#elif、#else、#endif,條件語句,支持部分邏輯運算符;
- #warning、#error,編譯器遇到后會報錯或警告,并顯示后面文本;
- #region、#endregion,將一段代碼視為給定名稱的一個塊;
- #line,用于改變編譯器在警告和錯誤中顯示的文件名和行號信息,如,#line 123 "Test.cs";
- #pragma,抑制(disable)或還原(restore)指定的編譯警告;
- #nullable,啟用(enable)或禁用(disable)可空引用類型
4、隱藏方法
在基類和派生類中存在簽名相同的方法,且無virtual與override修飾時,派生類就會隱藏基類方法;
要隱藏方法,可在方法聲明中加new關鍵字修飾,否則編譯器會警告,大多數情況下應重寫方法,而不是隱藏方法,隱藏方法會造成對于給定類的實例調用錯誤方法的危險;
可在派生類中使用base調用基類方法;
Pig pig = new();
pig.Hobby();
pig.BaseHobby();class Animal
{public void Hobby() => Console.WriteLine("Like run...");
}
class Pig : Animal
{new public void Hobby() => Console.WriteLine("Like eat...");public void BaseHobby() => base.Hobby();
}
5、顯示和隱式實現接口
隱式實現接口示例:
MyLog myLog = new MyLog();
myLog.Log("this is a log!");
interface ILogger
{void Log(string message);
}class MyLog : ILogger
{public void Log(string message) => Console.WriteLine(message);
}
顯示實現接口,被實現成員沒有訪問修飾符,并且方法前帶有接口前綴;
對于顯示實現接口,使用MyLog類型變量時,不能訪問該接口,因為它是非公有的,只有使用接口類型可調用Log()方法;
使用顯示實現接口原因:①為了解決不同接口相同簽名方法的沖突;②向類外的代碼隱藏接口方法,但仍滿足接口契約;
示例如下:
ILogger myLog = new MyLog();
myLog.Log("this is a log!");
interface ILogger
{void Log(string message);
}class MyLog : ILogger
{void ILogger.Log(string message) => Console.WriteLine(message);
}
6、泛型約束
約束 | 說明 |
---|---|
where T : struct | 使用結構約束時,T必須為值類型 |
where T : class | 使用類約束時,T必須為引用類型 |
where T : class? | T必須是可空的或者不可為空的引用類型 |
where T : notnull | T必須是不可為空的類型,可為值類型或引用類型 |
where T : unmanaged | T必須是不可為空的非托管類型 |
where T : IFoo | 類型T必須實現接口IFoo |
where T : Foo | 類型T必須派生自基類Foo |
where T : new() | 構造函數約束,指定T必須有無參構造函數。不能為有參構造函數指定約束 |
where T1 : T2 | 使用約束時,可指定類型T1派生自泛型類型T2 |
7、字典初始化方式
Dictionary<int, string> dic = new Dictionary<int, string>() { { 1, "111" }, { 2, "bbb" } };
Dictionary<int, string> dic2 = new Dictionary<int, string>() { [1] = "111", [2] = "aaa" };
Console.WriteLine("{0}\t{1}", dic[1], dic2[1]);
8、集Set
?包含不重復的元素的集合稱為,“集(set)”;
.NET Core包含兩個集,他們都實現ISet<T>接口:
①HashSet<T>,包含不重復元素的無序散列表;
②SortedSet<T>,包含不重復元素的有序列表;
集的提供另一個Add()方法,其返回類型為bool值,說明是否添加了元素,若該元素已存在,就不添加,并返回false;
HashSet<int> set = new HashSet<int>() { 2, 1, 7, 0, 1, 2 };
foreach (int i in set)Console.Write($"{i} ");//輸出2 1 7 0
SortedSet<int> set2 = new SortedSet<int>() { 2, 1, 7, 0, 1, 2 };
foreach (int i in set2)Console.Write($"{i} ");//輸出0 1 2 7
9、有序集合
有序集合包括有序集、有序列表、有序字典,功能幾乎完全相同,但其性能有很大差異,有序列表使用的內存少,有序字典的元素檢索速度快。?
10、只讀字段與屬性?
只讀字段(readonly修飾的字段 ),在運行時通過構造函數賦值
只讀屬性,(set被private修飾),使用屬性初始化或在構造函數里初始化,如下:
public int Id { get; } = 23;