La résolution des surcharges en C# préfère les surcharges de type params
étendue
C# 13 a ajouté la prise en charge des paramètres params
déclarés avec des types de collection autres que les tableaux. En particulier, params ReadOnlySpan<T>
et params Span<T>
sont pris en charge, et la résolution des surcharges préfère un type d'étendue params
à un type de tableau params
lorsque les deux sont applicables.
.NET 9 a ajoutéparams
des surcharges d'étendue pour diverses méthodes dans les bibliothèques .NET de base. Ces méthodes avaient des surcharges préexistantes qui prenaient des tableaux params
. Lorsque vous recompilez le code avec des appels existants à ces méthodes où les arguments sont transmis sous forme développée, le compilateur se lie désormais à la surcharge de l'étendue params
.
La nouvelle liaison entraîne une rupture potentielle pour les appels existants à ces surcharges dans les expressions lambda Expression, qui ne prennent pas en charge les instances ref struct
. Dans ces cas, le compilateur C# 13 signale une erreur lors de la liaison avec la surcharge de l'étendue params
.
Par exemple, considérez string.Join()
:
using System;
using System.Linq.Expressions;
Expression<Func<string, string, string>> join =
(x, y) => string.Join("", x, y);
Lorsqu’il est compilé avec .NET 8, l’appel est lié à Join(String, String[]), sans erreurs.
Lorsqu’il est compilé avec C# 13 et .NET 9, l’appel est lié à Join(String, ReadOnlySpan<String>)et, étant donné que l’appel se trouve dans une arborescence d’expressions , les erreurs suivantes sont signalées :
erreur CS8640 : L’arborescence d’expressions ne peut pas contenir de valeur de struct ref ou de type restreint « ReadOnlySpan ». erreur CS9226 : Une arborescence d’expressions ne peut pas contenir une forme développée de paramètres non-tableau.
Version introduite
.NET 9
Comportement précédent
Avant C# 13, les paramètres params
étaient limités uniquement aux types de tableaux. Les appels à ces méthodes sous forme développée ont abouti uniquement à des instances de tableau implicites, qui sont prises en charge dans les expressions lambda Expression.
Nouveau comportement
Avec C# 13 et .NET 9, pour les méthodes avec des surcharges qui acceptent des types de tableaux params
et des types de "span" params
, la résolution de surcharge préfère la surcharge de "span" params
. Un tel appel crée une instance d'étendue implicite sur le site d'appel. Pour les appels à l'intérieur d'expressions lambda Expression, l'instance d'étendue ref struct
implicite est signalée comme une erreur de compilation.
Type de changement cassant
Cette modification peut affecter la compatibilité source .
Raison de la modification
Les nouvelles surcharges de méthode ont été ajoutées pour des raisons de performance. La prise en charge de l'étendue params
permet au compilateur d'éviter une allocation pour l'argument params
sur le site d'appel.
Action recommandée
Si votre code est affecté, la solution de contournement recommandée consiste à appeler la méthode avec un tableau explicite afin que l’appel soit lié à la surcharge de tableau params
.
Pour l’exemple précédent, utilisez new string[] { ... }
:
Expression<Func<string, string, string>> join =
(x, y) => string.Join("", new string[] { x, y });
API affectées
- 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>)