C# のオーバーロード解決では、
C# 13 では、配列以外のコレクション型で宣言された params パラメーターのサポートが追加されました。 特に、params ReadOnlySpan<T>とparams Span<T>がサポートされており、オーバーロードの解決では、両方が該当する場合、params配列型よりもparamsスパン型が優先されます。
.NET 9 では、コア .NET ライブラリ のさまざまなメソッドの params スパン オーバーロードが追加されました 。 これらのメソッドには、 params 配列を受け取る既存のオーバーロードがありました。 拡張形式で引数が渡されるメソッドの既存の呼び出しでコードを再コンパイルすると、コンパイラは params スパン オーバーロードにバインドされるようになります。
新しいバインドによって、Expression ラムダ式内のこれらのオーバーロードに対する既存の呼び出しに破壊的変更が発生する可能性があります。それは、ref struct インスタンスをサポートしていないためです。 このような場合、C# 13 コンパイラは、 params スパン オーバーロードにバインドするときにエラーを報告します。
たとえば、次の string.Join()を考えてみましょう。
using System;
using System.Linq.Expressions;
Expression<Func<string, string, string>> join =
(x, y) => string.Join("", x, y);
.NET 8 でコンパイルすると、呼び出しはエラーなしで Join(String, String[])にバインドされます。
C# 13 および .NET 9 でコンパイルすると、呼び出しは Join(String, ReadOnlySpan<String>)にバインドされ、呼び出しが 式ツリー内にあるため、次のエラーが報告されます。
エラー CS8640: 式ツリーに ref 構造体または制限型 'ReadOnlySpan' の値を含めることはできません。 エラー CS9226: 式ツリーに、配列以外のパラメーターの展開形式が含まれていない可能性があります
導入されたバージョン
.NET 9
以前の動作
C# 13 より前では、 params パラメーターは配列型のみに制限されていました。 展開された形式でこれらのメソッドを呼び出すと、暗黙的な配列インスタンスのみが生成され、 Expression ラムダ式でサポートされます。
新しい動作
C# 13 および .NET 9 では、 params 配列型と params スパン型を受け取るオーバーロードを持つメソッドの場合、オーバーロードの解決では、 params スパン オーバーロードが優先されます。 このような呼び出しでは、呼び出しサイトに暗黙的なスパン インスタンスが作成されます。
Expressionラムダ式内の呼び出しの場合、暗黙的なref structスパン インスタンスはコンパイラ エラーとして報告されます。
破壊的変更の種類
この変更は ソースの互換性に影響を与える可能性があります。
変更の理由
パフォーマンス上の理由から、新しいメソッドのオーバーロードが追加されました。
params span のサポートにより、コンパイラは呼び出しサイトで params 引数の割り当てを回避できます。
推奨されるアクション
コードが影響を受ける場合、メソッドを明示的な配列で呼び出して、呼び出しが params 配列オーバーロードにバインドされるようにすることをお勧めします。
前の例では、 new string[] { ... }を使用します。
Expression<Func<string, string, string>> join =
(x, y) => string.Join("", new string[] { x, y });
影響を受ける API
- System.Collections.Immutable.ImmutableArray.Create<T>(ReadOnlySpan<T>)
- System.Collections.Immutable.ImmutableArray<T>.AddRange(ReadOnlySpan<T>)
- System.Collections.Immutable.ImmutableArray<T>.InsertRange(Int32, ReadOnlySpan<T>)
- System.Collections.Immutable.ImmutableArray<T>.Builder.AddRange(ReadOnlySpan<T>)
- System.Collections.Immutable.ImmutableArray<T>.Builder.AddRange<TDerived>(ReadOnlySpan<TDerived>)
- System.Collections.Immutable.ImmutableHashSet.Create<T>(IEqualityComparer<T>, ReadOnlySpan<T>)
- System.Collections.Immutable.ImmutableHashSet.Create<T>(ReadOnlySpan<T>)
- System.Collections.Immutable.ImmutableList.Create<T>(ReadOnlySpan<T>)
- System.Collections.Immutable.ImmutableQueue.Create<T>(ReadOnlySpan<T>)
- System.Collections.Immutable.ImmutableSortedSet.Create<T>(IComparer<T>, ReadOnlySpan<T>)
- System.Collections.Immutable.ImmutableSortedSet.Create<T>(ReadOnlySpan<T>)
- System.Collections.Immutable.ImmutableStack.Create<T>(ReadOnlySpan<T>)
- System.Console.Write(String, ReadOnlySpan<Object>)
- System.Console.WriteLine(String, ReadOnlySpan<Object>)
- System.Diagnostics.Metrics.Counter<T>.Add(T, ReadOnlySpan<KeyValuePair<String,Object>>)
- System.Diagnostics.Metrics.Gauge<T>.Record(T, ReadOnlySpan<KeyValuePair<String,Object>>)
- System.Diagnostics.Metrics.UpDownCounter<T>.Add(T, ReadOnlySpan<KeyValuePair<String,Object>>)
- System.Diagnostics.Metrics.Histogram<T>.Record(T, ReadOnlySpan<KeyValuePair<String,Object>>)
- System.MemoryExtensions.TryWrite(Span<Char>, IFormatProvider, CompositeFormat, Int32, ReadOnlySpan<Object>)
- System.Delegate.Combine(ReadOnlySpan<Delegate>)
- System.String.Concat(ReadOnlySpan<Object>)
- System.String.Concat(ReadOnlySpan<String>)
- System.String.Format(IFormatProvider, CompositeFormat, ReadOnlySpan<Object>)
- System.String.Format(IFormatProvider, String, ReadOnlySpan<Object>)
- System.String.Format(String, ReadOnlySpan<Object>)
- System.String.Join(Char, ReadOnlySpan<Object>)
- System.String.Join(Char, ReadOnlySpan<String>)
- System.String.Join(String, ReadOnlySpan<Object>)
- System.String.Join(String, ReadOnlySpan<String>)
- System.String.Split(ReadOnlySpan<Char>)
- System.CodeDom.Compiler.IndentedTextWriter.Write(String, ReadOnlySpan<Object>)
- System.CodeDom.Compiler.IndentedTextWriter.WriteLine(String, ReadOnlySpan<Object>)
- System.IO.Path.Combine(ReadOnlySpan<String>)
- System.IO.Path.Join(ReadOnlySpan<String>)
- System.IO.StreamWriter.Write(String, ReadOnlySpan<Object>)
- System.IO.StreamWriter.WriteLine(String, ReadOnlySpan<Object>)
- System.IO.TextWriter.Write(String, ReadOnlySpan<Object>)
- System.IO.TextWriter.WriteLine(String, ReadOnlySpan<Object>)
- System.Text.StringBuilder.AppendFormat(IFormatProvider, CompositeFormat, ReadOnlySpan<Object>)
- System.Text.StringBuilder.AppendFormat(IFormatProvider, String, ReadOnlySpan<Object>)
- System.Text.StringBuilder.AppendFormat(String, ReadOnlySpan<Object>)
- System.Text.StringBuilder.AppendJoin(Char, ReadOnlySpan<Object>)
- System.Text.StringBuilder.AppendJoin(Char, ReadOnlySpan<String>)
- System.Text.StringBuilder.AppendJoin(String, ReadOnlySpan<Object>)
- System.Text.StringBuilder.AppendJoin(String, ReadOnlySpan<String>)
- System.Threading.CancellationTokenSource.CreateLinkedTokenSource(ReadOnlySpan<CancellationToken>)
- System.Threading.Tasks.Task.WaitAll(ReadOnlySpan<Task>)
- System.Threading.Tasks.Task.WhenAll(ReadOnlySpan<Task>)
- System.Threading.Tasks.Task.WhenAll<TResult>(ReadOnlySpan<Task<TResult>>)
- System.Threading.Tasks.Task.WhenAny(ReadOnlySpan<Task>)
- System.Threading.Tasks.Task.WhenAny<TResult>(ReadOnlySpan<Task<TResult>>)
- JsonArray(JsonNodeOptions, ReadOnlySpan<JsonNode>)
- JsonArray(ReadOnlySpan<JsonNode>)
- System.Text.Json.Serialization.Metadata.JsonTypeInfoResolver.Combine(ReadOnlySpan<IJsonTypeInfoResolver>)
こちらも参照ください
.NET