メモ
この記事は機能仕様についてです。 仕様は、機能の設計ドキュメントとして使用できます。 これには、提案された仕様の変更および機能の設計と開発時に必要な情報が含まれます。 これらの記事は、提案された仕様の変更が決定され、現在の ECMA 仕様に組み込まれるまで公開されます。
機能の仕様と行われた実装では、いくつかの違いがあることがあります。 これらの違いは、関連する言語設計ミーティング (LDM) メモに取り上げられています。
機能仕様を C# 言語標準に導入するプロセスの詳細については、仕様に関する記事を参照してください。
チャンピオンの課題: https://github.com/dotnet/csharplang/issues/6065
まとめ
これは、最初のネイティブ整数機能 (仕様) のリビジョンであり、nint/nuint 型は基になる型 System.IntPtr/System.UIntPtr とは異なっていました。
つまり、nint/nuint は、System.IntPtr に関連して / のために行うように、System.UIntPtrintSystem.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# では、、sbyte、byte、short、ushort、int、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。
- 構築型以外の、unmanaged_typeのフィールドのみを含む、ユーザー定義のすべての struct_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、ulongまたは に変換できます。 [...]
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₁がTask<S₁>であり、T₂はTask<S₂>であり、S₁はS₂よりも優れた変換ターゲットです -
T₁はS₁またはS₁?で、S₁は符号付き整数型、T₂はS₂またはS₂?で、S₂は符号なし整数型です。 具体的には: [...]
12.8.12 要素アクセス
[...] argument_list 内の式の数は、 array_type のランクと同じである必要があります。各式は、intuint、nintnuint、long、または ulong, の型であるか、暗黙的にこれらの型の 1 つ以上に変換可能である必要があります。
11.8.12.2 配列へのアクセス
[...] argument_list 内の式の数は、 array_type のランクと同じである必要があります。各式は、intuint、nintnuint、long、または ulong, の型であるか、暗黙的にこれらの型の 1 つ以上に変換可能である必要があります。
形[...] 式 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、uint、nint、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が負でない場合は空の上位ビット位置が 0 に設定され、xが負の場合は 1 に設定されます。xがuint、nuint、またはulongの型の場合、xの下位ビットは破棄され、残りのビットは右にシフトされ、上位の空のビット位置は 0 に設定されます。符号なしの右シフト:
... nint operator >>>(nint x, int count); nuint operator >>>(nuint x, int count);
定義済みの演算子の場合、シフトするビット数は次のように計算されます: [...]
-
xの型がnintまたはnuintの場合、シフト カウントは、32 ビット プラットフォームの下位 5 ビットのcount、または 64 ビット プラットフォームの下位 6 ビットの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 であるか、これらの型の 1 つ以上に暗黙的に変換できます。 配列要素アクセスの結果は変数、つまりインデックスによって選択された配列要素です。
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);
ポインター型 P の式 T* と、型 N、int、uintnint、または nuintの式 に基づき、long と ulong の式は、P + Nによって指定されたアドレスに N + P を加えた結果として得られる、型 T* のポインター値を計算します。 同様に、式 P – N は、T* によって指定されたアドレスから N * sizeof(T) を減算した型 P のポインター値を計算します。
さまざまな考慮事項
重大な変更
この設計の主な影響の 1 つは、System.IntPtr と System.UIntPtr が一部の組み込み演算子 (変換、単項、二項) を取得することです。
これには checked 演算子が含まれます。つまり、これらの型に対する次の演算子はオーバーフロー時にスローされます。
IntPtr + intIntPtr - intIntPtr -> intlong -> IntPtrvoid* -> IntPtr
メタデータ エンコード
この設計は、nint と nuint が System.IntPtr を使用せずに、単に System.UIntPtr および System.Runtime.CompilerServices.NativeIntegerAttribute として出力できることを意味します。
同様に、メタデータの読み込み時に NativeIntegerAttribute を無視できます。
C# feature specifications