次の方法で共有


.NET 6.0.100 から .NET 7.0.100 以降の Roslyn での破壊的変更

このドキュメントでは、.NET 6 の一般リリース (.NET SDK バージョン 6.0.100) から .NET 7 の一般リリース (.NET SDK バージョン 7.0.100) までの Roslyn での既知の破壊的変更を示します。

非同期メソッドでは、制限された型のすべてのローカルは許可されません

Visual Studio 2022 バージョン 17.6p1 で導入されました

非同期メソッドでは、制限された型のローカルは許可されません。 しかし、以前のバージョンでは、コンパイラは暗黙的に宣言されたローカルに気付けませんでした。 たとえば、foreachusing のステートメントあるいは分解などにおいて。
現在、このように暗黙的に宣言されるローカル変数も許可されていません。

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)の両方が適用可能と見なされるようになりました (比較については、d1d2の例を参照してください)。 以前は、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 の組み込み演算子が基になる型に適用されます。 つまり、このようなプラットフォームでは、IntPtrUIntPtr には組み込みの 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
}

考えられる回避策は次のとおりです。

  1. コンテキスト unchecked 指定する
  2. 数値型の IntPtr/UIntPtr を使用せずにプラットフォーム/TFM にダウングレードする

また、 IntPtr/UIntPtr とその他の数値型の間の暗黙的な変換は、このようなプラットフォームでは標準変換として扱われます。 これは、場合によってはオーバーロードの解決に影響を与える可能性があります。

これらの変更により、ユーザー コードがチェックされていないコンテキストのオーバーフロー例外に依存していた場合、またはチェックされたコンテキストでオーバーフロー例外が想定されていない場合に、動作の変更が発生する可能性があります。 このような動作の変化を検出し、適切なアクションを実行するために、 アナライザーが 7.0 に追加 されました。 アナライザーは、潜在的な動作の変更に関する診断を生成します。既定では情報の重大度ですが、editorconfig を通じて警告にアップグレードできます。

System.UIntPtr と System.Int32 の追加

.NET SDK 7.0.100、Visual Studio 2022 バージョン 17.3 で導入されました。

プラットフォームで数値IntPtrUIntPtr型 (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'
}

考えられる回避策は次のとおりです。

  1. UIntPtr.Add(UIntPtr, int)メソッドを使用します。UIntPtr.Add(x, y)
  2. 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) { }
}

考えられる回避策は次のとおりです。

  1. 外部スコープから名前がシャドウされないように、型パラメーターまたはパラメーターの名前を変更します。
  2. 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
}

考えられる回避策は次のとおりです。

  1. System.Diagnostics.CodeAnalysis.UnscopedRefAttributeを使用して、参照をスコープ外としてマークします。

    static ref T ReturnOutParamByRef<T>([UnscopedRef] out T t)
    {
        t = default;
        return ref t; // ok
    }
    
  2. パラメーターを 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# のバージョンを対象とする新しいコンパイラでこの機能がサポートされていたバグが修正されます。

考えられる回避策は次のとおりです。

  1. ref struct型をstructまたはclass型に変更します。
  2. <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 以降でコンパイラ エラーが発生します。

この変更を回避するには、次のいずれかの変更を行います。

  1. 変換が不要になるようにパラメーターの型を変更します。
  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
{
}

回避策には、次の変更が含まれます。

  1. 戻り値の型として @var を使用します。
  2. コンパイラが戻り値の型を決定するように、明示的な戻り値の型を削除します。

挿入文字列ハンドラーとインデクサーの初期化

.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) {}
}

回避策には、次の変更が含まれます。

  1. 挿入文字列ハンドラーから受信タイプを削除します。
  2. 引数をインデクサーで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#5552dotnet/roslyn#58581 を参照してください。

C# で変数を既定値に初期化するには、 new()defaultの 2 つの方法があります。 クラスの場合、 new は新しいインスタンスを作成し、 defaultnullを返すので、違いは明らかです。 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 の問題を参照してください。