このドキュメントでは、.NET 6 の一般リリース (.NET SDK バージョン 6.0.100) から .NET 7 の一般リリース (.NET SDK バージョン 7.0.100) までの Roslyn での既知の破壊的変更を示します。
非同期メソッドでは、制限された型のすべてのローカルは許可されません
Visual Studio 2022 バージョン 17.6p1 で導入されました
非同期メソッドでは、制限された型のローカルは許可されません。 しかし、以前のバージョンでは、コンパイラは暗黙的に宣言されたローカルに気付けませんでした。 たとえば、foreach
や using
のステートメントあるいは分解などにおいて。
現在、このように暗黙的に宣言されるローカル変数も許可されていません。
ref struct RefStruct { public void Dispose() { } }
public class C
{
public async Task M()
{
RefStruct local = default; // disallowed
using (default(RefStruct)) { } // now disallowed too ("error CS9104: A using statement resource of this type cannot be used in async methods or async lambda expressions")
}
}
https://github.com/dotnet/roslyn/pull/66264 を参照してください
ポインターは常に安全でないコンテキストにある必要があります。
Visual Studio 2022 バージョン 17.6 で導入されました
以前の SDK では、コンパイラは、ポインターを参照できる場所を許可する場合があり、その場所を安全でないと明示的にマークする必要はありません。
ここで、 unsafe
修飾子が存在する必要があります。
たとえば、 using Alias = List<int*[]>;
を using unsafe Alias = List<int*[]>;
に変更して有効にする必要があります。
void Method(Alias a) ...
などの使用方法は、unsafe void Method(Alias a) ...
に変更する必要があります。
この規則は、 using
エイリアス宣言 (C# 12 より前の unsafe
修飾子を許可しなかった) を除き、無条件です。
そのため、 using
宣言の場合、言語バージョンが C# 12 以降として選択されている場合にのみルールが有効になります。
System.TypedReference がマネージドと見なされる
Visual Studio 2022 バージョン 17.6 で導入されました
今後、System.TypedReference
のタイプは管理されると見なされます。
unsafe
{
TypedReference* r = null; // warning: This takes the address of, gets the size of, or declares a pointer to a managed type
var a = stackalloc TypedReference[1]; // error: Cannot take the address of, get the size of, or declare a pointer to a managed type
}
Ref 安全性エラーはラムダ式からデリゲートへの変換には影響しません
Visual Studio 2022 バージョン 17.5 で導入されました
ラムダ本体で報告された ref 安全性エラーは、ラムダ式がデリゲート型に変換できるかどうかに影響しなくなりました。 この変更は、オーバーロードの解決に影響する可能性があります。
次の例では、M(x => ...)
の呼び出しは Visual Studio 17.5 ではあいまいです。ラムダ本体内でM(D1)
を呼び出すとM(D2)
で ref 安全性が得られますが、F(ref x, ref y)
とM(D1)
の両方が適用可能と見なされるようになりました (比較については、d1
とd2
の例を参照してください)。 以前は、M(D2)
オーバーロードが適用されないと見なされたため、呼び出しはM(D1)
に明確にバインドされていました。
using System;
ref struct R { }
delegate R D1(R r);
delegate object D2(object o);
class Program
{
static void M(D1 d1) { }
static void M(D2 d2) { }
static void F(ref R x, ref Span<int> y) { }
static void F(ref object x, ref Span<int> y) { }
static void Main()
{
// error CS0121: ambiguous between: 'M(D1)' and 'M(D2)'
M(x =>
{
Span<int> y = stackalloc int[1];
F(ref x, ref y);
return x;
});
D1 d1 = x1 =>
{
Span<int> y1 = stackalloc int[1];
F(ref x1, ref y1); // error CS8352: 'y2' may expose referenced variables
return x1;
};
D2 d2 = x2 =>
{
Span<int> y2 = stackalloc int[1];
F(ref x2, ref y2); // ok: F(ref object x, ref Span<int> y)
return x2;
};
}
}
オーバーロード解決の変更を回避するには、ラムダ パラメーターまたはデリゲートに明示的な型を使用します。
// ok: M(D2)
M((object x) =>
{
Span<int> y = stackalloc int[1];
F(ref x, ref y); // ok: F(ref object x, ref Span<int> y)
return x;
});
行の先頭にある生文字列の補間。
Visual Studio 2022 バージョン 17.5 で導入されました
.NET SDK 7.0.100 以前では、次の内容が誤って許可されました。
var x = $"""
Hello
{1 + 1}
World
""";
これは、行の内容 (補間が開始される場所を含む) が最終的な """;
行と同じ空白で始まる必要があるというルールに違反しました。 これで、上記を次のように記述する必要があります。
var x = $"""
Hello
{1 + 1}
World
""";
メソッドの推定デリゲート型には、既定のパラメーター値と params
修飾子が含まれます
Visual Studio 2022 バージョン 17.5 で導入されました
.NET SDK 7.0.100 以前では、メソッドから推論されたデリゲート型は、次のコードに示すように、既定のパラメーター値と params
修飾子を無視しました。
void Method(int i = 0, params int[] xs) { }
var action = Method; // System.Action<int, int[]>
DoAction(action, 1); // ok
void DoAction(System.Action<int, int[]> a, int p) => a(p, new[] { p });
.NET SDK 7.0.200 以降では、このようなメソッドは、同じ既定のパラメーター値と params
修飾子を持つ匿名合成デリゲート型として推論されます。
この変更により、次に示すように上記のコードが中断される可能性があります。
void Method(int i = 0, params int[] xs) { }
var action = Method; // delegate void <anonymous delegate>(int arg1 = 0, params int[] arg2)
DoAction(action, 1); // error CS1503: Argument 1: cannot convert from '<anonymous delegate>' to 'System.Action<int, int[]>'
void DoAction(System.Action<int, int[]> a, int p) => a(p, new[] { p });
この変更の詳細については、関連する 提案を参照してください。
明確な割り当て分析を目的として、非同期ローカル関数の呼び出しは待機中として扱われなくなりました
Visual Studio 2022 バージョン 17.5 で導入されました
明確な割り当て分析のために、非同期ローカル関数の呼び出しは待機中として扱われなくなったため、ローカル関数は完全に実行されるとは見なされません。 根拠については、 https://github.com/dotnet/roslyn/issues/43697 を参照してください。
次のコードでは、明確な割り当てエラーが報告されます。
public async Task M()
{
bool a;
await M1();
Console.WriteLine(a); // error CS0165: Use of unassigned local variable 'a'
async Task M1()
{
if ("" == String.Empty)
{
throw new Exception();
}
else
{
a = true;
}
}
}
INoneOperation
属性のノードは現在 IAttributeOperation
ノードです。
Visual Studio 2022 バージョン 17.5、.NET SDK バージョン 7.0.200 で導入されました
以前のバージョンのコンパイラでは、属性の IOperation
ツリーが INoneOperation
ノードでルート化されていました。
属性のネイティブ サポートが追加されました。つまり、ツリーのルートが IAttributeOperation
になりました。 以前のバージョンの .NET SDK アナライザーを含む一部のアナライザーは、このツリー形状を予期していないため、発生したときに誤って警告 (または警告に失敗する可能性があります) します。 これに対する回避策は次のとおりです。
- 可能であれば、アナライザーのバージョンを更新します。 .NET SDK 以前のバージョンの Microsoft.CodeAnalysis.FxCopAnalyzers を使用している場合は、Microsoft.CodeAnalysis.NetAnalyzers 7.0.0-preview1.22464.1 以降に更新してください。
- アナライザーからの誤検知を、この変更を考慮するバージョンで更新できるようになるまで抑制します。
ref
構造体の型テストはサポートされていません。
Visual Studio 2022 バージョン 17.4 で導入されました
ref
構造体型が 'is' または 'as' 演算子で使用されている場合、一部のシナリオでは、コンパイラは以前、実行時に常に型テストに関する誤った警告を報告し、実際の型チェックを省略し、不適切な動作を引き起こしていました。 実行時に正しくない動作が可能だった場合、コンパイラは代わりにエラーを生成するようになりました。
ref struct G<T>
{
public void Test()
{
if (this is G<int>) // Will now produce an error, used to be treated as always `false`.
{
ref local からの未使用の結果は逆参照です。
Visual Studio 2022 バージョン 17.4 で導入されました
ref
ローカル変数が値によって参照されていても、結果が使用されない場合 (破棄に割り当てられるなど)、結果は以前は無視されていました。 コンパイラはそのローカルを逆参照し、副作用が観察されるようにします。
ref int local = Unsafe.NullRef<int>();
_ = local; // Will now produce a `NullReferenceException`
型に名前を付けることはできません scoped
Visual Studio 2022 バージョン 17.4 で導入されました。 C# 11 以降では、型に scoped
名前を付けることはできません。 コンパイラは、このようなすべての型名に関するエラーを報告します。 これを回避するには、型名とすべての使用法を @
でエスケープする必要があります。
class scoped {} // Error CS9056
class @scoped {} // No error
ref scoped local; // Error
ref scoped.nested local; // Error
ref @scoped local2; // No error
これは、 scoped
が変数宣言の修飾子になり、ref 型の ref
の後に予約されているためです。
型に名前を付けることはできません file
Visual Studio 2022 バージョン 17.4 で導入されました。 C# 11 以降では、型に file
名前を付けることはできません。 コンパイラは、このようなすべての型名に関するエラーを報告します。 これを回避するには、型名とすべての使用法を @
でエスケープする必要があります。
class file {} // Error CS9056
class @file {} // No error
これは、 file
が型宣言の修飾子になったため行われました。
この変更の詳細については、関連する csharplang の問題を参照してください。
#line スパン ディレクティブ内で必要なスペース
.NET SDK 6.0.400、Visual Studio 2022 バージョン 17.3 で導入されました。
#line
span ディレクティブが C# 10 で導入されたとき、特定の間隔は必要ありませんでした。
たとえば、これは有効です: #line(1,2)-(3,4)5"file.cs"
。
Visual Studio 17.3 では、コンパイラは最初のかっこ、文字オフセット、およびファイル名の前にスペースが必要です。
したがって、スペースが追加されない限り、上記の例は解析に失敗します: #line (1,2)-(3,4) 5 "file.cs"
。
System.IntPtr および System.UIntPtr の評価済み演算子
.NET SDK 7.0.100、Visual Studio 2022 バージョン 17.3 で導入されました。
プラットフォームで 数値IntPtr
型と UIntPtr
型がサポートされている場合 ( System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
の存在によって示されます)、 nint
および nuint
の組み込み演算子が基になる型に適用されます。
つまり、このようなプラットフォームでは、IntPtr
と UIntPtr
には組み込みの checked
演算子があり、オーバーフローが発生した場合にスローする可能性があります。
IntPtr M(IntPtr x, int y)
{
checked
{
return x + y; // may now throw
}
}
unsafe IntPtr M2(void* ptr)
{
return checked((IntPtr)ptr); // may now throw
}
考えられる回避策は次のとおりです。
- コンテキスト
unchecked
指定する - 数値型の
IntPtr
/UIntPtr
を使用せずにプラットフォーム/TFM にダウングレードする
また、 IntPtr
/UIntPtr
とその他の数値型の間の暗黙的な変換は、このようなプラットフォームでは標準変換として扱われます。 これは、場合によってはオーバーロードの解決に影響を与える可能性があります。
これらの変更により、ユーザー コードがチェックされていないコンテキストのオーバーフロー例外に依存していた場合、またはチェックされたコンテキストでオーバーフロー例外が想定されていない場合に、動作の変更が発生する可能性があります。 このような動作の変化を検出し、適切なアクションを実行するために、 アナライザーが 7.0 に追加 されました。 アナライザーは、潜在的な動作の変更に関する診断を生成します。既定では情報の重大度ですが、editorconfig を通じて警告にアップグレードできます。
System.UIntPtr と System.Int32 の追加
.NET SDK 7.0.100、Visual Studio 2022 バージョン 17.3 で導入されました。
プラットフォームで数値型IntPtr
UIntPtr
型 (System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
の存在によって示される) がサポートされている場合、+(UIntPtr, int)
で定義されている演算子System.UIntPtr
は使用できなくなります。
代わりに、 System.UIntPtr
型と System.Int32
の式を追加すると、エラーが発生します。
UIntPtr M(UIntPtr x, int y)
{
return x + y; // error: Operator '+' is ambiguous on operands of type 'nuint' and 'int'
}
考えられる回避策は次のとおりです。
-
UIntPtr.Add(UIntPtr, int)
メソッドを使用します。UIntPtr.Add(x, y)
- 2 番目のオペランド
nuint
に型x + unchecked((nuint)y)
へのチェックなしのキャストを適用してください。
メソッドまたはローカル関数の属性における Nameof 演算子
.NET SDK 6.0.400、Visual Studio 2022 バージョン 17.3 で導入されました。
言語バージョンが C# 11 以降の場合、メソッドの属性の nameof
演算子は、そのメソッドの型パラメーターをスコープ内に取り込みます。 ローカル関数にも同じことが当てはまります。
メソッドの属性の nameof
演算子は、型パラメーターまたはパラメーターによって、そのメソッドのパラメーターをスコープ内に取り込みます。 ローカル関数、ラムダ、デリゲート、インデクサーにも同様です。
たとえば、次のようなエラーになります。
class C
{
class TParameter
{
internal const string Constant = """";
}
[MyAttribute(nameof(TParameter.Constant))]
void M<TParameter>() { }
}
class C
{
class parameter
{
internal const string Constant = """";
}
[MyAttribute(nameof(parameter.Constant))]
void M(int parameter) { }
}
考えられる回避策は次のとおりです。
- 外部スコープから名前がシャドウされないように、型パラメーターまたはパラメーターの名前を変更します。
-
nameof
演算子の代わりに文字列リテラルを使用します。
参照渡しで out パラメーターを返すことはできません
.NET SDK 7.0.100、Visual Studio 2022 バージョン 17.3 で導入されました。
言語バージョン C# 11 以降、または .NET 7.0 以降では、 out
パラメーターを参照で返すことはできません。
static ref T ReturnOutParamByRef<T>(out T t)
{
t = default;
return ref t; // error CS8166: Cannot return a parameter by reference 't' because it is not a ref parameter
}
考えられる回避策は次のとおりです。
System.Diagnostics.CodeAnalysis.UnscopedRefAttribute
を使用して、参照をスコープ外としてマークします。static ref T ReturnOutParamByRef<T>([UnscopedRef] out T t) { t = default; return ref t; // ok }
パラメーターを
ref
渡すメソッド シグネチャを変更します。static ref T ReturnRefParamByRef<T>(ref T t) { t = default; return ref t; // ok }
ref 構造体のインスタンス メソッドは、スコープ外の ref パラメーターをキャプチャする可能性があります
.NET SDK 7.0.100、Visual Studio 2022 バージョン 17.4 で導入されました。
言語バージョン C# 11 以降、または .NET 7.0 以降では、スコープ外のref struct
またはref
パラメーターをキャプチャするin
インスタンス メソッドの呼び出しが想定されます。
R<int> Use(R<int> r)
{
int i = 42;
r.MayCaptureArg(ref i); // error CS8350: may expose variables referenced by parameter 't' outside of their declaration scope
return r;
}
ref struct R<T>
{
public void MayCaptureArg(ref T t) { }
}
ref
またはin
パラメーターが ref struct
インスタンス メソッドでキャプチャされない場合は、scoped ref
またはscoped in
としてパラメーターを宣言します。
R<int> Use(R<int> r)
{
int i = 42;
r.CannotCaptureArg(ref i); // ok
return r;
}
ref struct R<T>
{
public void CannotCaptureArg(scoped ref T t) { }
}
メソッド ref 構造体の戻りエスケープ分析は、ref 引数の ref エスケープに依存します
.NET SDK 7.0.100、Visual Studio 2022 バージョン 17.4 で導入されました。
言語バージョン C# 11 以降、または .NET 7.0 以降では、戻り値またはref struct
パラメーターとしてメソッド呼び出しから返されるout
は、メソッド呼び出しに対するすべてのおよびref
引数が in
の場合にのみ安全にエスケープできます。
in
引数には、暗黙的な既定のパラメーター値を含めることができます。
ref struct R { }
static R MayCaptureArg(ref int i) => new R();
static R MayCaptureDefaultArg(in int i = 0) => new R();
static R Create()
{
int i = 0;
// error CS8347: Cannot use a result of 'MayCaptureArg(ref int)' because it may expose
// variables referenced by parameter 'i' outside of their declaration scope
return MayCaptureArg(ref i);
}
static R CreateDefault()
{
// error CS8347: Cannot use a result of 'MayCaptureDefaultArg(in int)' because it may expose
// variables referenced by parameter 'i' outside of their declaration scope
return MayCaptureDefaultArg();
}
ref
またはin
引数がref struct
戻り値に取り込まれていない場合は、scoped ref
またはscoped in
としてパラメーターを宣言することが考えられます。
static R CannotCaptureArg(scoped ref int i) => new R();
static R Create()
{
int i = 0;
return CannotCaptureArg(ref i); // ok
}
ref
から ref struct
までの引数は __arglist
内でスコープ外と見なされる
.NET SDK 7.0.100、Visual Studio 2022 バージョン 17.4 で導入されました。
言語バージョン C# 11 以降、または .NET 7.0 以降では、ref
型へのref struct
は、__arglist
に引数として渡されるとスコープ外の参照と見なされます。
ref struct R { }
class Program
{
static void MayCaptureRef(__arglist) { }
static void Main()
{
var r = new R();
MayCaptureRef(__arglist(ref r)); // error: may expose variables outside of their declaration scope
}
}
符号なし右シフト演算子
.NET SDK 6.0.400、Visual Studio 2022 バージョン 17.3 で導入されました。 この言語では、"Unsigned Right Shift" 演算子 (>>>
) のサポートが追加されました。
これにより、ユーザー定義の "Unsigned Right Shift" 演算子を通常のメソッドとして実装するメソッドを使用する機能が無効になります。
たとえば、ある言語 (VB または C# 以外) で開発された既存のライブラリがあり、型 C1
の "Unsigned Right Shift" ユーザー定義演算子を公開しています。
次のコードは、前に正常にコンパイルするために使用されます。
static C1 Test1(C1 x, int y) => C1.op_UnsignedRightShift(x, y); //error CS0571: 'C1.operator >>>(C1, int)': cannot explicitly call operator or accessor
考えられる回避策は、 >>>
演算子の使用に切り替える方法です。
static C1 Test1(C1 x, int y) => x >>> y;
ref 構造体としての Foreach 列挙子
.NET SDK 6.0.300、Visual Studio 2022 バージョン 17.2 で導入されました。 ref 構造体列挙子型を使用する foreach
は、言語バージョンが 7.3 以前に設定されている場合にエラーを報告します。
これにより、サポートされる前に C# のバージョンを対象とする新しいコンパイラでこの機能がサポートされていたバグが修正されます。
考えられる回避策は次のとおりです。
-
ref struct
型をstruct
またはclass
型に変更します。 -
<LangVersion>
要素を 7.3 以降にアップグレードします。
非同期 foreach
では、明示的なインターフェイスの実装よりもパターン ベースの DisposeAsync
が優先されます。 IAsyncDisposable.DisposeAsync()
.NET SDK 6.0.300、Visual Studio 2022 バージョン 17.2 で導入されました。非同期foreach
は、DisposeAsync()
ではなく、パターンベースのIAsyncDisposable.DisposeAsync()
メソッドを使用してバインドすることを好みます。
たとえば、DisposeAsync()
のIAsyncEnumerator<int>.DisposeAsync()
メソッドではなく、AsyncEnumerator
が選択されます。
await foreach (var i in new AsyncEnumerable())
{
}
struct AsyncEnumerable
{
public AsyncEnumerator GetAsyncEnumerator() => new AsyncEnumerator();
}
struct AsyncEnumerator : IAsyncDisposable
{
public int Current => 0;
public async ValueTask<bool> MoveNextAsync()
{
await Task.Yield();
return false;
}
public async ValueTask DisposeAsync()
{
Console.WriteLine("PICKED");
await Task.Yield();
}
ValueTask IAsyncDisposable.DisposeAsync() => throw null; // no longer picked
}
この変更により、宣言された型でパブリック DisposeAsync
メソッドが表示される仕様違反が修正されましたが、明示的なインターフェイス実装はインターフェイス型への参照のみを使用して表示されます。
このエラーを回避するには、型からパターン ベース DisposeAsync
メソッドを削除します。
変換された文字列を既定の引数として許可しない
.NET SDK 6.0.300、Visual Studio 2022 バージョン 17.2 で導入されました。 C# コンパイラは、文字列定数の参照変換に関連する正しくない既定の引数値を受け入れ、ソースで指定された既定値ではなく定数値として null
を出力します。 Visual Studio 17.2 では、これはエラーになります。
roslyn#59806 を参照してください。
この変更により、コンパイラの仕様違反が修正されます。 既定の引数はコンパイル時定数である必要があります。 以前のバージョンでは、次のコードが許可されています。
void M(IEnumerable<char> s = "hello")
上記の宣言では、 string
から IEnumerable<char>
への変換が必要です。 コンパイラはこのコンストラクトを許可し、引数の値として null
を出力します。 上記のコードでは、17.2 以降でコンパイラ エラーが発生します。
この変更を回避するには、次のいずれかの変更を行います。
- 変換が不要になるようにパラメーターの型を変更します。
- 前の動作を復元するには、既定の引数の値を
null
に変更します。
明示的なラムダ式の戻り値の型としてのコンテキスト キーワード var
.NET SDK 6.0.200、Visual Studio 2022 バージョン 17.1 で導入されました。 コンテキスト キーワード var は、明示的なラムダ戻り値の型として使用できません。
この変更により、がラムダ式の戻り値の型の自然な型のままであることを確認することで、var
が有効になります。
var
という名前の型があり、var
の明示的な戻り値の型 (型) を使用してラムダ式を定義すると、このエラーが発生する可能性があります。
using System;
F(var () => default); // error CS8975: The contextual keyword 'var' cannot be used as an explicit lambda return type
F(@var () => default); // ok
F(() => default); // ok: return type is inferred from the parameter to F()
static void F(Func<var> f) { }
public class var
{
}
回避策には、次の変更が含まれます。
- 戻り値の型として
@var
を使用します。 - コンパイラが戻り値の型を決定するように、明示的な戻り値の型を削除します。
挿入文字列ハンドラーとインデクサーの初期化
.NET SDK 6.0.200、Visual Studio 2022 バージョン 17.1 で導入されました。 挿入文字列ハンドラーを受け取り、コンストラクターの入力としてレシーバーを必要とするインデクサーは、オブジェクト初期化子では使用できません。
この変更により、インデクサー初期化子が挿入文字列ハンドラーを使用し、挿入文字列ハンドラーがインデクサーの受信側をコンストラクターのパラメーターとして受け取るエッジ ケース シナリオは禁止されます。 この変更の理由は、このシナリオによって、まだ初期化されていない変数にアクセスする可能性があるということです。 次の例を考えてみましょう。
using System.Runtime.CompilerServices;
// error: Interpolated string handler conversions that reference
// the instance being indexed cannot be used in indexer member initializers.
var c = new C { [$""] = 1 };
class C
{
public int this[[InterpolatedStringHandlerArgument("")] CustomHandler c]
{
get => ...;
set => ...;
}
}
[InterpolatedStringHandler]
class CustomHandler
{
// The constructor of the string handler takes a "C" instance:
public CustomHandler(int literalLength, int formattedCount, C c) {}
}
回避策には、次の変更が含まれます。
- 挿入文字列ハンドラーから受信タイプを削除します。
- 引数をインデクサーで
string
に変更します。
ref、readonly ref、in、out をパラメーターとして使用したり、アンマネージ呼び出し元のみのメソッドに対して戻ったりすることはできません
out
は、UnmanagedCallersOnly
で属性付けされたメソッドの戻り値/パラメーターでは使用できません。
この変更はバグ修正です。 戻り値とパラメーターは blittable ではありません。 引数または戻り値を参照渡しで渡すと、未定義の動作が発生する可能性があります。 次の宣言はコンパイルされません。
using System.Runtime.InteropServices;
[UnmanagedCallersOnly]
static ref int M1() => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
[UnmanagedCallersOnly]
static ref readonly int M2() => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
[UnmanagedCallersOnly]
static void M3(ref int o) => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
[UnmanagedCallersOnly]
static void M4(in int o) => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
[UnmanagedCallersOnly]
static void M5(out int o) => throw null; // error CS8977: Cannot use 'ref', 'in', or 'out' in a method attributed with 'UnmanagedCallersOnly'.
回避策は、by 参照修飾子を削除することです。
パターンにおいて、長さとカウントは非負であると見なされる
.NET SDK 6.0.200、Visual Studio 2022 バージョン 17.1 で導入されました。 カウント可能な型とインデックス可能な型のLength
プロパティは、パターンとスイッチの包含と完全性の分析を目的として、負でないと見なされます。
これらの型は、暗黙的なインデクサーおよびリスト パターンで使用できます。
Length
プロパティとCount
プロパティは、int
として型指定されていても、パターンを分析するときに負でないと見なされます。 次のサンプル メソッドについて考えてみましょう。
string SampleSizeMessage<T>(IList<T> samples)
{
return samples switch
{
// This switch arm prevents a warning before 17.1, but will never happen in practice.
// Starting with 17.1, this switch arm produces a compiler error.
// Removing it won't introduce a warning.
{ Count: < 0 } => throw new InvalidOperationException(),
{ Count: 0 } => "Empty collection",
{ Count: < 5 } => "Too small",
{ Count: < 20 } => "reasonable for the first pass",
{ Count: < 100 } => "reasonable",
{ Count: >= 100 } => "fine",
};
}
void M(int[] i)
{
if (i is { Length: -1 }) {} // error: impossible under assumption of non-negative length
}
17.1 より前では、最初のスイッチ アームでは、 Count
が負であることをテストして、使用可能なすべての値がカバーされていないという警告を回避する必要がありました。 17.1 以降では、最初のスイッチ アームでコンパイラ エラーが生成されます。 回避策は、無効なケースに対して追加されたスイッチ アームを削除することです。
この変更は、リスト パターンの追加の一環として行われました。 コレクションで Length
または Count
プロパティを使用するたびに負でないと見なされる場合、処理規則の一貫性が高くなります。
言語設計の問題の変更の詳細を確認できます。
回避策として、到達不可能な条件を持つスイッチアームを取り外します。
構造体にフィールド初期化子を追加するには、明示的に宣言されたコンストラクターが必要です
struct
フィールド初期化子を使用する型宣言には、明示的に宣言されたコンストラクターを含める必要があります。 さらに、すべてのフィールドは、struct
インスタンス コンストラクターで: this()
初期化子を持たない場合は確実に割り当てる必要があり、以前に割り当てられていないフィールドは追加されたコンストラクターまたはフィールド初期化子から割り当てられなければなりません。
dotnet/csharplang#5552、dotnet/roslyn#58581 を参照してください。
C# で変数を既定値に初期化するには、 new()
と default
の 2 つの方法があります。 クラスの場合、 new
は新しいインスタンスを作成し、 default
は null
を返すので、違いは明らかです。
default
の場合、構造体は各フィールド/プロパティを独自の既定値に設定したインスタンスを返すので、構造体の違いはより微妙です。 C# 10 で構造体のフィールド初期化子を追加しました。 フィールド初期化子は、明示的に宣言されたコンストラクターが実行される場合にのみ実行されます。 重要なことに、 default
を使用したり、 struct
型の配列を作成したりしても実行されません。
17.0 では、フィールド初期化子があっても宣言されたコンストラクターがない場合、フィールド初期化子を実行するパラメーターなしのコンストラクターが合成されます。 ただし、これはコンストラクター宣言を追加または削除することを意味し、パラメーターなしのコンストラクターが合成されるかどうかに影響を与える可能性があり、その結果、 new()
の動作が変更される可能性があります。
この問題に対処するため、.NET SDK 6.0.200 (VS 17.1) では、コンパイラはパラメーターなしのコンストラクターを合成しなくなりました。
struct
にフィールド初期化子が含まれており、明示的なコンストラクターがない場合、コンパイラはエラーを生成します。
struct
にフィールド初期化子がある場合は、コンストラクターを宣言する必要があります。それ以外の場合、フィールド初期化子は実行されないためです。
さらに、フィールド初期化子を持たないすべてのフィールドは、コンストラクターにstruct
初期化子がない限り、各: this()
コンストラクターに割り当てる必要があります。
たとえば、次のようになります。
struct S // error CS8983: A 'struct' with field initializers must include an explicitly declared constructor.
{
int X = 1;
int Y;
}
回避策は、コンストラクターを宣言することです。 フィールドが以前に割り当てられていない場合を除き、このコンストラクターは空のパラメーターなしのコンストラクターになります。多くの場合、このコンストラクターは空のパラメーターなしのコンストラクターになります。
struct S
{
int X = 1;
int Y;
public S() { Y = 0; } // ok
}
書式指定子に中かっこを含めることができない
.NET SDK 6.0.200、Visual Studio 2022 バージョン 17.1 で導入されました。 挿入文字列の書式指定子には、中かっこ ( {
または }
) を含めできません。 以前のバージョンでは、 {{
はエスケープされた {
として解釈され、 }}
は書式指定子のエスケープされた }
文字として解釈されていました。 書式指定子の最初の }
char は補間を終了し、 {
char はエラーになります。
これにより、補間された文字列処理は、 System.String.Format
の処理と一致します。
using System;
Console.WriteLine($"{{{12:X}}}");
//prints now: "{C}" - not "{X}}"
X
は大文字の 16 進数の形式で、 C
は 12 の 16 進数の値です。
回避策は、書式指定文字列内の余分な中かっこを削除することです。
この変更の詳細については、関連する roslyn の問題を参照してください。
型に名前を付けることはできません required
Visual Studio 2022 バージョン 17.3 で導入されました。 C# 11 以降では、型に required
名前を付けることはできません。 コンパイラは、このようなすべての型名に関するエラーを報告します。 これを回避するには、型名とすべての使用法を @
でエスケープする必要があります。
class required {} // Error CS9029
class @required {} // No error
これは、 required
がプロパティとフィールドのメンバー修飾子になったため行われました。
この変更の詳細については、関連する csharplang の問題を参照してください。
Roslyn breaking changes