注意
本文是功能規格。 規格可作為功能的設計檔。 其中包含建議的規格變更,以及功能設計和開發期間所需的資訊。 這些文章會發佈,直到提議的規格變更完成並併併入目前的ECMA規格為止。
功能規格與已完成實作之間可能有一些差異。 這些差異是在的相關
您可以在 規範的文章中深入瞭解將功能規範納入 C# 語言標準的過程。
冠軍問題:https://github.com/dotnet/csharplang/issues/6065
總結
這是初始原生整數特徵的修訂(規格),其中 nint/nuint 類型與基礎類型不同 System.IntPtr/System.UIntPtr。
簡言之,我們現在會將 nint/nuint 視為簡單類型別名 System.IntPtr/System.UIntPtr,就像 int 與 System.Int32相關時一樣。
System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr 運行時間功能旗標會觸發這個新行為。
設計
8.3.5 簡單類型
C# 提供一組預先定義的 struct 類型,稱為簡單型別。 簡單類型是透過關鍵詞來識別,但這些關鍵詞只是 struct 命名空間中預先定義 System 類型的別名,如下表所述。
| 關鍵詞 | 別名類型 |
|---|---|
sbyte |
System.SByte |
byte |
System.Byte |
short |
System.Int16 |
ushort |
System.UInt16 |
int |
System.Int32 |
uint |
System.UInt32 |
nint |
System.IntPtr |
nuint |
System.UIntPtr |
long |
System.Int64 |
ulong |
System.UInt64 |
char |
System.Char |
float |
System.Single |
double |
System.Double |
bool |
System.Boolean |
decimal |
System.Decimal |
[...]
8.3.6 整數類型
C# 支援 11 整數類型:sbyte、byte、short、ushort、int、uint、nint、nuint、long、ulong和 char。 [...]
8.8 非受控類型
換句話說,unmanaged_type 是下列之一:
-
sbyte、byte、short、ushort、int、uint、nint、nuint、long、ulong、char、float、double、decimal或bool。 - 任何 enum_type。
- 任何使用者定義 struct_type 不是建構的類型,且只包含 unmanaged_type的字段。
- 在不安全的程式碼中,任何 pointer_type。
10.2.3 隱含數值轉換
隱含數值轉換如下:
- 從
sbyte到short、int、nint、long、float、double或decimal。 - 從
byte到short、ushort、int、uint、nint、nuint、long、ulong、float、double或decimal。 - 從
short到int、nint、long、float、double或decimal。 - 從
ushort到int、uint、nint、nuint、long、ulong、float、double或decimal。 - 從
int到nint、long、float、double或decimal。 - 從
uint到nuint、long、ulong、float、double或decimal。 -
從
nint到long、float、double或decimal。 -
從
nuint到ulong、float、double或decimal。 - 從
long到float、double或decimal。 - 從
ulong到float、double或decimal。 - 從
char到ushort、int、uint、nint、nuint、long、ulong、float、double或decimal。 - 從
float到double。
[...]
10.2.11 隱含常數表達式轉換
隱含常數表示式轉換允許下列轉換:
-
類型的
int可以轉換成類型sbyte、byte、short、ushort、uint、nint、nuint或ulong,前提是 constant_expression 的值在目的類型範圍內。 [...]
10.3.2 明確數值轉換
明確數值轉換是從 numeric_type 轉換成另一個隱含數值轉換不存在的另一個 numeric_type:
- 從
sbyte到byte、ushort、uint、nuint、ulong或char。 - 從
byte到sbyte或char。 - 從
short到sbyte、byte、ushort、uint、nuint、ulong或char。 - 從
ushort到sbyte、byte、short或char。 - 從
int到sbyte、byte、short、ushort、uint、nuint、ulong或char。 - 從
uint到sbyte、byte、short、ushort、int、nint或char。 - 從
long到sbyte、byte、short、ushort、int、uint、nint、nuint、ulong或char。 -
從
nint到sbyte、byte、short、ushort、int、uint、nuint、ulong或char。 -
從
nuint到sbyte、byte、short、ushort、int、uint、nint、long或char。 - 從
ulong到sbyte、byte、short、ushort、int、uint、nint、nuint、long或char。 - 從
char到sbyte、byte或short。 - 從
float到sbyte、byte、short、ushort、int、uint、nint、nuint、long、ulong、char或decimal。 - 從
double到sbyte、byte、short、ushort、int、uint、nint、nuint、long、ulong、char、float或decimal。 - 從
decimal到sbyte、byte、short、ushort、int、uint、nint、nuint、long、ulong、char、float或double。
[...]
10.3.3 明確列舉轉換
明確的列舉轉換有如下幾種:
- 從
sbyte、byte、short、ushort、int、uint、、nint、nuint、、long、ulong、char、float、double或decimal轉換到任何 之 enum_type。 - 從任何 enum_type 到
sbyte、byte、short、ushort、int、uint、nint、nuint、long、ulong、char、float、double或decimal。 - 從任何 enum_type 到任何其他 enum_type。
12.6.4.7 更好的轉換目標
假設有兩種類型 T₁ 和 T₂,如果下列其中一項保留,T₁ 是 目標:
- 存在從
T₁到T₂的隱含轉換,而且不存在從T₂到T₁的隱含轉換 -
T₁是Task<S₁>、T₂Task<S₂>,而S₁是比S₂更好的轉換目標 -
T₁是S₁或S₁?,其中S₁是帶正負號整數型別,T₂是S₂或S₂?,其中S₂是無符號整數型別。 具體來說: [...]
12.8.12 元素存取
[...]argument_list 中的運算式數目應與 array_type的等級相同,而且每個表達式的類型應為 int、uint、nint、nuint、long、ulong, 或隱含轉換成其中一或多個類型。
11.8.12.2 陣組存取
[...]argument_list 中的運算式數目應與 array_type的等級相同,而且每個表達式的類型應為 int、uint、nint、nuint、long、ulong, 或隱含轉換成其中一或多個類型。
[...]表單 P[A]的陣列記憶體取的運行時間處理,其中 P 是 array_type 的 primary_no_array_creation_expression,而 A 是 argument_list,包含下列步驟: [...]
-
argument_list 的索引表達式會依左至右的順序進行評估。 在評估每個索引表示式之後,會執行下列其中一種類型的隱含轉換:
int、uint、nint、nuint、long、ulong。 在此清單中,選擇有隱含轉換存在的第一個類型。 [...]
12.8.16 後置遞增和遞減運算符
一元運算子超載解析用於選擇特定的運算子實作。 下列類型存在預先定義的 ++ 和 -- 運算符:sbyte、byte、short、ushort、int、uint、nint、nuint、long、ulong、char、float、double、decimal及任何列舉類型。
12.9.2 一元加號運算符
預先定義的一元加運算符如下:
...
nint operator +(nint x);
nuint operator +(nuint x);
12.9.3 一元減號運算符
預先定義的一元減號運算符如下:
整數否定:
... nint operator –(nint x);
12.8.16 後置遞增和遞減運算符
下列類型有預先定義的 ++ 和 -- 運算符:sbyte、byte、short、ushort、int、uint、nint、nuint、long、ulong、char、float、double、decimal及任何列舉類型。
11.7.19 預設值表達式
此外,如果類型是下列其中一個實值型別,default_value_expression 是常數表達式:sbyte、byte、short、ushort、int、uintnint、nuint、long、ulong、char、float、double、decimal、bool, 或任何列舉型別。
12.9.5 位補碼運算符
預先定義的位補碼運算符如下:
...
nint operator ~(nint x);
nuint operator ~(nuint x);
12.9.6 前置詞遞增和遞減運算符
下列類型有預先定義的 ++ 和 -- 運算符:sbyte、byte、short、ushort、int、uint、nint、nuint、long、ulong、char、float、double、decimal及任何列舉類型。
12.10 算術運算元
12.10.2 乘法運算符
預先定義的乘法運算符如下所列。 運算子都會計算 x 和 y的乘積。
整數乘法:
... nint operator *(nint x, nint y); nuint operator *(nuint x, nuint y);
12.10.3 除法運算符
預先定義的除法運算符如下所列。 所有運算元都會計算 x 和 y的商數。
整數除法:
... nint operator /(nint x, nint y); nuint operator /(nuint x, nuint y);
12.10.4 餘數運算符
預先定義的餘數運算符如下所列。 運算子都會計算 x 與 y之間除法的餘數。
整數餘數:
... nint operator %(nint x, nint y); nuint operator %(nuint x, nuint y);
12.10.5 加法運算符
整數加法:
... nint operator +(nint x, nint y); nuint operator +(nuint x, nuint y);
12.10.6 減法運算符
整數減法:
... nint operator –(nint x, nint y); nuint operator –(nuint x, nuint y);
12.11 位移運算子
預先定義的移位運算符如下所列。
左移:
... nint operator <<(nint x, int count); nuint operator <<(nuint x, int count);右移:
... nint operator >>(nint x, int count); nuint operator >>(nuint x, int count);>>運算子會將x根據以下描述的位元數向右移位。當
x的類型為int、nint或long時,會捨棄x低階位,其餘位會向右移位,如果x為非負數,則會將高階空白位位置設定為零,如果x為負數,則會設定為 1。當
x類型為uint、nuint或ulong時,會捨棄x低階位,其餘位會向右移位,而高階空白位位置會設定為零。無符號右移:
... nint operator >>>(nint x, int count); nuint operator >>>(nuint x, int count);
針對預先定義的運算符,要移位的位數會計算如下: [...]
- 當
x的類型是nint或nuint時,移位計數由 32 位元平台上的低位五位count或 64 位元平台上的低位六位count確定。
12.12 關係型和型別測試運算符
12.12.2 整數比較運算符
預先定義的整數比較運算符如下:
...
bool operator ==(nint x, nint y);
bool operator ==(nuint x, nuint y);
bool operator !=(nint x, nint y);
bool operator !=(nuint x, nuint y);
bool operator <(nint x, nint y);
bool operator <(nuint x, nuint y);
bool operator >(nint x, nint y);
bool operator >(nuint x, nuint y);
bool operator <=(nint x, nint y);
bool operator <=(nuint x, nuint y);
bool operator >=(nint x, nint y);
bool operator >=(nuint x, nuint y);
12.12 邏輯運算符
12.12.2 整數邏輯運算符
預先定義的整數邏輯運算符如下:
...
nint operator &(nint x, nint y);
nuint operator &(nuint x, nuint y);
nint operator |(nint x, nint y);
nuint operator |(nuint x, nuint y);
nint operator ^(nint x, nint y);
nuint operator ^(nuint x, nuint y);
12.22 常數表達式
常數表達式可以是實值型別或參考型別。 如果常數表達式是實值型別,它必須是下列其中一種類型:sbyte、byte、short、ushort、int、uint、nint、nuint、long、ulong、char、float、double、decimal、bool, 或任何列舉型別。
[...]
隱含常數表達式轉換允許類型 int 常數表達式轉換成 sbyte、byte、short、ushort、uint、nint、nuint、 或 ulong,前提是常數表達式的值在目的型別的範圍內。
17.4 陣列元素存取
數位元素是使用表單 的 A[I₁, I₂, ..., Iₓ] 表示式來存取,其中 A 是陣列類型的運算式,而每個 Iₑ 都是類型 int、uint、nint、nuint、long、ulong或可以隱含轉換成其中一或多個類型的表達式。 陣列專案存取的結果是變數,也就是索引所選取的陣列專案。
23.5 指標轉換
23.5.1 一般
[...]
此外,在不安全的情境中,可用的明確轉換集合會擴充,以包含下列明確的指標轉換:
- 從任何 pointer_type 到任何其他 pointer_type。
- 從
sbyte、byte、short、ushort、int、uint、nint、nuint、long或ulong到任何 pointer_type。 - 從任何 pointer_type 到
sbyte、byte、short、ushort、int、uint、nint、nuint、long或ulong。
23.6.4 指標元素存取
在形式 P[E]的指標元素存取中,P 應為指標型別而非 void*的表達式,而 E 應為可以被隱式轉換為 int、uint、nint、nuint、long或 ulong的表達式。
23.6.7 指標算術
在不安全的內容中,+ 運算子和 – 運算符可以套用至除了 void*以外的所有指標類型值。 因此,對於每個指標類型 T*,會隱含定義下列運算符:
[...]
T* operator +(T* x, nint y);
T* operator +(T* x, nuint y);
T* operator +(nint x, T* y);
T* operator +(nuint x, T* y);
T* operator -(T* x, nint y);
T* operator -(T* x, nuint y);
假設指標類型的表達式 PT*,以及類型為 N、int、uintnint或 nuint的 表達式,表達式 long 和 ulong 計算類型 P + N 的指標值,其結果就是將 N + P 新增至 T*指定的位址。 同樣地,表達式 P – N 會計算出從 T*指定的位址中減去 N * sizeof(T) 所得到的類型 P 的指標值。
各種考慮
重大變更
此設計的主要影響之一是 System.IntPtr 和 System.UIntPtr 獲得一些內建運算元(轉換、一元和二進位)。
這些運算子包括 checked 運算子,這表示這些類型的下列運算子現在會在溢位時擲回:
IntPtr + intIntPtr - intIntPtr -> intlong -> IntPtrvoid* -> IntPtr
元數據編碼
此設計意味著,nint 和 nuint 可以簡單地發射為 System.IntPtr 和 System.UIntPtr,無需使用 System.Runtime.CompilerServices.NativeIntegerAttribute。
同樣地,載入元數據時 NativeIntegerAttribute 可以忽略。