Rozpoznawanie przeciążeń w języku C# preferuje przeciążenia typu span params
.
Język C# 13 dodał obsługę parametrów params
zadeklarowanych przy użyciu typów kolekcji innych niż tablice. W szczególności obsługiwane są params ReadOnlySpan<T>
i params Span<T>
, a rozdzielanie przeciążenia preferuje typ zakresu params
zamiast typu tablicowego params
, gdy oba mają zastosowanie.
Platforma .NET 9 dodała przeciążenia params
typu span dla różnych metod w bibliotekach podstawowych .NET. Te metody miały wcześniej istniejące przeciążenia obsługujące tablice params
. Podczas ponownego kompilowania kodu z istniejącymi wywołaniami tych metod, gdzie argumenty są przekazywane w postaci rozwiniętej, kompilator powiąże teraz z funkcją przeciążeniową zakresu params
.
Nowe powiązanie prowadzi do potencjalnej zmiany powodującej niezgodność istniejących wywołań dla tych przeciążeń w Expression wyrażeniach lambda, które nie obsługują ref struct
wystąpień. W takich przypadkach kompilator języka C# 13 zgłasza błąd podczas wiązania z przeciążeniem params
span.
Rozważmy na przykład string.Join()
:
using System;
using System.Linq.Expressions;
Expression<Func<string, string, string>> join =
(x, y) => string.Join("", x, y);
Po skompilowaniu przy użyciu platformy .NET 8 wywołanie wiąże się z Join(String, String[]), bez błędów.
Po skompilowaniu przy użyciu języków C# 13 i .NET 9 wywołanie wiąże się z Join(String, ReadOnlySpan<String>)i dlatego, że wywołanie znajduje się w drzewie wyrażeń , są zgłaszane następujące błędy:
błąd CS8640: Drzewo wyrażeń nie może zawierać wartości struktury ref lub typu ograniczonego "ReadOnlySpan". błąd CS9226: Drzewo wyrażeń nie może zawierać rozszerzonej formy parametrów innego typu niż tablica
Wprowadzona wersja
.NET 9
Poprzednie zachowanie
Przed C# 13 parametry params
były ograniczone tylko do typów tablic. Wywołania tych metod w rozszerzonej formie powodowały jedynie niejawne wystąpienia tablic, które są obsługiwane w wyrażeniach lambda Expression.
Nowe zachowanie
Dla języka C# 13 i .NET 9 w przypadku metod z przeciążeniami przyjmującymi typy tablic params
i typy span params
, rozdzielanie przeciążeń preferuje przeciążenie span params
. Takie wywołanie tworzy niejawne wystąpienie zakresu w miejscu wywołania. W przypadku wywołań w Expression wyrażeniach lambda wystąpienie niejawne ref struct
span jest zgłaszane jako błąd kompilatora.
Typ zmiany powodującej niezgodność
Ta zmiana może mieć wpływ na zgodność źródła .
Przyczyna zmiany
Nowe przeciążenia metody zostały dodane ze względów wydajności.
params
obsługa zakresu umożliwia kompilatorowi uniknięcie alokacji argumentu params
w miejscu wywołania.
Zalecana akcja
Jeśli dotyczy to kodu, zalecanym obejściem jest wywołanie metody z jawną tablicą, aby wywołanie wiązało się z przeciążeniem tablicy params
.
W poprzednim przykładzie użyj new string[] { ... }
:
Expression<Func<string, string, string>> join =
(x, y) => string.Join("", new string[] { x, y });
Interfejsy API, których dotyczy problem
- 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>)