Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Ce document répertorie les changements cassants connus dans Roslyn après la version générale de .NET 6 (kit SDK .NET version 6.0.100) jusqu'à la version générale de .NET 7 (kit SDK .NET version 7.0.100).
Toutes les variables locales des types restreints ne sont pas autorisées dans les méthodes asynchrones
Introduit dans Visual Studio 2022 version 17.6p1
Les variables locales de types restreints sont interdites dans les méthodes asynchrones. Toutefois, dans les versions antérieures, le compilateur n’a pas remarqué certains locaux déclarés implicitement. Par exemple, dans les instructions foreach
ou using
ou les déconstructions.
À présent, ces variables locales déclarées implicitement sont également interdites.
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")
}
}
Voir https://github.com/dotnet/roslyn/pull/66264
Les pointeurs doivent toujours être dans des contextes non sécurisés.
Introduit dans Visual Studio 2022 version 17.6
Dans les Kits de développement logiciel (SDK) précédents, le compilateur autorise parfois les emplacements où les pointeurs peuvent être référencés, sans marquer explicitement cet emplacement comme non sécurisé.
Maintenant, le unsafe
modificateur doit être présent.
Par exemple, using Alias = List<int*[]>;
doit être changé en using unsafe Alias = List<int*[]>;
pour être légal.
Une utilisation telle que void Method(Alias a) ...
doit être modifiée en unsafe void Method(Alias a) ...
.
La règle est inconditionnelle, à l’exception des using
déclarations d’alias (qui n’ont pas autorisé un unsafe
modificateur avant C# 12).
Par conséquent, pour les using
déclarations, la règle prend effet uniquement si la version de langue est choisie comme C# 12 ou version ultérieure.
System.TypedReference considéré comme géré
Introduit dans Visual Studio 2022 version 17.6
À l'avenir, le type System.TypedReference
est considéré comme étant sous gestion.
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
}
Les erreurs de sécurité Ref n’affectent pas la conversion d’une expression lambda en délégué
Introduit dans Visual Studio 2022 version 17.5
Les erreurs de sécurité Ref signalées dans un corps lambda n’affectent plus la convertibilité de l’expression lambda en un type délégué. Cette modification peut affecter la résolution des surcharges.
Dans l’exemple ci-dessous, l’appel à M(x => ...)
est ambigu avec Visual Studio 17.5, car les deux M(D1)
et M(D2)
sont désormais considérés comme applicables, même si l’appel au F(ref x, ref y)
corps lambda entraîne une sécurité ref avec M(D1)
(voir les exemples dans d1
et d2
pour la comparaison). Auparavant, l'appel était lié sans ambiguïté à M(D2)
, car la surcharge M(D1)
était considérée comme non applicable.
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;
};
}
}
Pour contourner les modifications de résolution de surcharge, utilisez des types explicites pour les paramètres lambda ou le délégué.
// 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;
});
Interpolations de chaîne brutes au début de la ligne.
Introduit dans Visual Studio 2022 version 17.5
Dans le Kit de développement logiciel (SDK) .NET 7.0.100 ou version antérieure, les informations suivantes ont été autorisées de manière erronée :
var x = $"""
Hello
{1 + 1}
World
""";
Cela a violé la règle selon laquelle le contenu des lignes (y compris l’emplacement où une interpolation commence) doit commencer par le même espace blanc que la ligne finale """;
. Il est maintenant nécessaire que les éléments ci-dessus soient écrits comme suit :
var x = $"""
Hello
{1 + 1}
World
""";
Le type de délégué déduit pour les méthodes inclut les valeurs par défaut des paramètres et le modificateur params
.
Introduit dans Visual Studio 2022 version 17.5
Dans le Kit de développement logiciel (SDK) .NET 7.0.100 ou version antérieure, les méthodes où les types délégués sont déduits ignorent les valeurs par défaut des paramètres et les modificateurs params
, comme illustré dans le code suivant :
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 });
Dans le Kit de développement logiciel (SDK) .NET 7.0.200 ou version ultérieure, ces méthodes sont déduites en tant que types délégués synthétisés anonymes avec les mêmes valeurs de paramètres et params
modificateurs par défaut.
Cette modification peut interrompre le code ci-dessus, comme illustré ci-dessous :
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 });
Vous pouvez en savoir plus sur ce changement dans la proposition associée.
Dans le cadre de l’analyse des affectations définitives, les appels de fonctions locales asynchrones ne sont plus traités comme étant attendus
Introduit dans Visual Studio 2022 version 17.5
Dans le cadre de l’analyse de l’affectation définie, les appels d’une fonction locale asynchrone ne sont plus traités comme étant attendus et, par conséquent, la fonction locale n’est pas considérée comme entièrement exécutée. Voir https://github.com/dotnet/roslyn/issues/43697 pour la justification.
Le code ci-dessous va maintenant signaler une erreur d’affectation définitive :
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
nœuds pour les attributs sont désormais des nœuds IAttributeOperation
.
Introduit dans Visual Studio 2022 version 17.5, sdk .NET version 7.0.200
Dans les versions précédentes du compilateur, l’arborescence IOperation
d’un attribut avait une racine avec un nœud INoneOperation
.
Nous avons ajouté la prise en charge native des attributs, ce qui signifie que la racine de l’arborescence est désormais un IAttributeOperation
. Certains analyseurs, y compris les versions antérieures des analyseurs du kit de développement logiciel (SDK) .NET, ne s’attendent pas à cette forme d’arborescence et avertiront de manière incorrecte (ou risquent de ne pas avertir) lors de sa rencontre. Les solutions de contournement sont les suivantes :
- Mettez à jour votre version de l’analyseur, si possible. Si vous utilisez le Kit de développement logiciel (SDK) .NET ou les versions antérieures de Microsoft.CodeAnalysis.FxCopAnalyzers, mettez à jour microsoft.CodeAnalysis.NetAnalyzers 7.0.0-preview1.22464.1 ou version ultérieure.
- Supprimez les faux positifs des analyseurs jusqu’à ce qu’ils puissent être mis à jour avec une version qui prend en compte cette modification.
Les tests de type pour les structures ref
ne sont pas pris en charge.
Introduit dans Visual Studio 2022 version 17.4
Lorsqu’un ref
type de struct est utilisé dans un opérateur « is » ou « as », dans certains scénarios, le compilateur signale auparavant un avertissement erroné concernant le test de type qui échoue toujours au moment de l’exécution, omettant la vérification de type réelle et conduisant à un comportement incorrect. Lorsque le comportement incorrect au moment de l’exécution était possible, le compilateur génère désormais une erreur à la place.
ref struct G<T>
{
public void Test()
{
if (this is G<int>) // Will now produce an error, used to be treated as always `false`.
{
Les résultats inutilisés de "ref local" sont des déréférencements.
Introduit dans Visual Studio 2022 version 17.4
Lorsqu’une ref
variable locale est référencée par valeur, mais que le résultat n’est pas utilisé (par exemple, affecté à un abandon), le résultat a été précédemment ignoré. Le compilateur déréférencera désormais cette variable locale, garantissant ainsi que tous les effets secondaires sont observés.
ref int local = Unsafe.NullRef<int>();
_ = local; // Will now produce a `NullReferenceException`
Les types ne peuvent pas être nommés scoped
Introduit dans Visual Studio 2022 version 17.4. À compter de C# 11, les types ne peuvent pas être nommés scoped
. Le compilateur signale une erreur sur tous ces noms de types. Pour contourner ce problème, le nom du type et toutes ses utilisations doivent être échappés avec un @
:
class scoped {} // Error CS9056
class @scoped {} // No error
ref scoped local; // Error
ref scoped.nested local; // Error
ref @scoped local2; // No error
Cette opération a été effectuée car scoped
est désormais un modificateur pour les déclarations de variables, réservé après ref
dans un type de référence.
Les types ne peuvent pas être nommés file
Introduit dans Visual Studio 2022 version 17.4. À compter de C# 11, les types ne peuvent pas être nommés file
. Le compilateur signale une erreur sur tous ces noms de types. Pour contourner ce problème, le nom du type et toutes ses utilisations doivent être échappés avec un @
:
class file {} // Error CS9056
class @file {} // No error
Cela a été effectué car file
est désormais un modificateur pour les déclarations de type.
Vous pouvez en savoir plus sur cette modification dans le problème csharplang associé.
Espaces requis dans les directives d’étendue #line
Introduit dans le Kit de développement logiciel (SDK) .NET 6.0.400, Visual Studio 2022 version 17.3.
Lorsque la directive sur l’étendue #line
a été introduite en C# 10, elle n’exigeait aucun espacement particulier.
Par exemple, il s’agit d’une valeur valide : #line(1,2)-(3,4)5"file.cs"
.
Dans Visual Studio 17.3, le compilateur requiert des espaces avant la première parenthèse, le décalage de caractères et le nom de fichier.
Par conséquent, l’exemple ci-dessus ne parvient pas à analyser, sauf si des espaces sont ajoutés : #line (1,2)-(3,4) 5 "file.cs"
.
Opérateurs vérifiés sur System.IntPtr et System.UIntPtr
Introduit dans le Kit de développement logiciel (SDK) .NET 7.0.100, Visual Studio 2022 version 17.3.
Lorsque la plateforme prend en charge les types numériquesIntPtr
et UIntPtr
, (comme indiqué par la présence de System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
), les opérateurs intégrés de nint
et nuint
s’appliquent à ces types sous-jacents.
Cela signifie que sur ces plateformes, IntPtr
et UIntPtr
disposent d’opérateurs checked
intégrés, qui peuvent désormais générer une exception en cas de dépassement.
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
}
Les solutions de contournement possibles sont les suivantes :
- Spécifier le
unchecked
contexte - Passez à une plate-forme/TFM sans types numériques
IntPtr
/UIntPtr
En outre, les conversions implicites entre IntPtr
/UIntPtr
d’autres types numériques sont traitées comme des conversions standard sur ces plateformes. Cela peut affecter la résolution de surcharge dans certains cas.
Ces modifications peuvent entraîner une modification comportementale si le code utilisateur dépendait des exceptions de dépassement dans un contexte non vérifié, ou s’il ne s’attendait pas à des exceptions de dépassement dans un contexte vérifié. Un analyseur a été ajouté dans la version 7.0 pour aider à détecter ces modifications comportementales et à prendre les mesures appropriées. L’analyseur produira des diagnostics sur les changements de comportement potentiels, qui sont par défaut de gravité info, mais peuvent être mis à niveau vers des avertissements via editorconfig.
Ajout de System.UIntPtr et System.Int32
Introduit dans le Kit de développement logiciel (SDK) .NET 7.0.100, Visual Studio 2022 version 17.3.
Lorsque la plateforme prend en charge les types numériquesIntPtr
( UIntPtr
comme indiqué par la présence de System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr
), l’opérateur +(UIntPtr, int)
défini dans System.UIntPtr
ne peut plus être utilisé.
Au lieu de cela, l’ajout d’expressions de types System.UIntPtr
et System.Int32
entraîne une erreur :
UIntPtr M(UIntPtr x, int y)
{
return x + y; // error: Operator '+' is ambiguous on operands of type 'nuint' and 'int'
}
Les solutions de contournement possibles sont les suivantes :
- Utilisez la
UIntPtr.Add(UIntPtr, int)
méthode :UIntPtr.Add(x, y)
- Appliquez un transtypage non vérifié au type
nuint
sur le deuxième opérande :x + unchecked((nuint)y)
Nom de l’opérateur dans l’attribut d’une méthode ou d’une fonction locale
Introduit dans le Kit de développement logiciel (SDK) .NET 6.0.400, Visual Studio 2022 version 17.3.
Lorsque la version du langage est C# 11 ou ultérieure, un opérateur nameof
dans un attribut sur une méthode rend les paramètres de type de cette méthode disponibles. Il en va de même pour les fonctions locales.
Un opérateur nameof
dans un attribut d’une méthode, ses paramètres de type ou ses paramètres met les paramètres de cette méthode dans l’étendue. Il en va de même pour les fonctions locales, les lambdas, les délégués et les indexeurs.
Par exemple, ceux-ci seront désormais des erreurs :
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) { }
}
Les solutions de contournement possibles sont les suivantes :
- Renommez le paramètre de type ou le paramètre pour éviter de masquer le nom de l’étendue externe.
- Utilisez une chaîne littérale au lieu de l’opérateur
nameof
.
Impossible de retourner un paramètre de sortie par référence.
Introduit dans le Kit de développement logiciel (SDK) .NET 7.0.100, Visual Studio 2022 version 17.3.
Avec la version de langage C# 11 ou ultérieure, ou avec .NET 7.0 ou version ultérieure, un out
paramètre ne peut pas être retourné par référence.
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
}
Les solutions de contournement possibles sont les suivantes :
Utilisez
System.Diagnostics.CodeAnalysis.UnscopedRefAttribute
pour marquer la référence comme hors étendue.static ref T ReturnOutParamByRef<T>([UnscopedRef] out T t) { t = default; return ref t; // ok }
Modifiez la signature de méthode pour passer le paramètre par
ref
.static ref T ReturnRefParamByRef<T>(ref T t) { t = default; return ref t; // ok }
La méthode d’instance sur ref struct peut capturer des paramètres ref hors étendue
Introduit dans le Kit de développement logiciel (SDK) .NET 7.0.100, Visual Studio 2022 version 17.4.
Avec la version de langage C# 11 ou ultérieure, ou avec .NET 7.0 ou version ultérieure, un appel de méthode d’instance ref struct
est considéré comme capturant des paramètres non-délimités ref
ou 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) { }
}
Une solution de contournement possible, si le paramètre ref
ou in
n'est pas capturé dans la méthode d'instance ref struct
, consiste à le déclarer en tant que scoped ref
ou 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) { }
}
L’analyse d’échappement de la structure de référence de la méthode dépend de l’échappement de référence des arguments de référence
Introduit dans le Kit de développement logiciel (SDK) .NET 7.0.100, Visual Studio 2022 version 17.4.
Avec la version de langage C# 11 ou ultérieure, ou avec .NET 7.0 ou ultérieure, un ref struct
renvoyé par un appel de méthode, soit comme valeur de retour, soit dans un paramètre out
, ne peut échapper en toute sécurité que si tous les arguments ref
et in
de l’appel de méthode peuvent échapper en toute sécurité en tant que référence.
Les in
arguments peuvent inclure des valeurs de paramètre par défaut implicites.
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();
}
Une solution de contournement possible, si l'argument ref
ou in
n'est pas capturé dans la valeur de retour ref struct
, consiste à déclarer le paramètre comme scoped ref
ou scoped in
.
static R CannotCaptureArg(scoped ref int i) => new R();
static R Create()
{
int i = 0;
return CannotCaptureArg(ref i); // ok
}
argument ref
à ref struct
considéré comme hors de portée dans __arglist
Introduit dans le Kit de développement logiciel (SDK) .NET 7.0.100, Visual Studio 2022 version 17.4.
Avec la version de langage C# 11 ou ultérieure, ou avec .NET 7.0 ou version ultérieure, un type ref
vers ref struct
est considéré comme une référence non limitée lorsqu'on la passe comme argument à __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
}
}
Opérateur de décalage vers la droite non signé
Introduit dans le Kit de développement logiciel (SDK) .NET 6.0.400, Visual Studio 2022 version 17.3. La langue a ajouté la prise en charge d’un opérateur « Unsigned Right Shift » (>>>
).
Cela désactive la possibilité d’utiliser des méthodes implémentant des opérateurs « Unsigned Right Shift » définis par l’utilisateur en tant que méthodes régulières.
Par exemple, il existe une bibliothèque existante développée dans un langage (autre que VB ou C#) qui expose un opérateur défini par l’utilisateur « Unsigned Right Shift » pour le type C1
.
Le code suivant compilait avec succès avant :
static C1 Test1(C1 x, int y) => C1.op_UnsignedRightShift(x, y); //error CS0571: 'C1.operator >>>(C1, int)': cannot explicitly call operator or accessor
Une solution possible consiste à utiliser l’opérateur >>>
:
static C1 Test1(C1 x, int y) => x >>> y;
Énumérateur Foreach en tant que ref struct
Introduit dans le Kit de développement logiciel (SDK) .NET 6.0.300, Visual Studio 2022 version 17.2. Une foreach
utilisation d’un type d’énumérateur ref signale une erreur si la version du langage est définie sur la version 7.3 ou antérieure.
Cela résout un bogue dans lequel la fonctionnalité a été prise en charge dans les compilateurs plus récents ciblant une version de C# avant sa prise en charge.
Les solutions de contournement possibles sont les suivantes :
- Remplacez le
ref struct
type par un typestruct
ouclass
. - Mettez à niveau l’élément
<LangVersion>
vers la version 7.3 ou ultérieure.
Async foreach
préfère un modèle basé sur DisposeAsync
plutôt qu'une implémentation explicite d'interface de IAsyncDisposable.DisposeAsync()
Introduit dans le Kit de développement logiciel (SDK) .NET 6.0.300, Visual Studio 2022 version 17.2. Une async foreach
préfère lier à l’aide d’une méthode basée sur DisposeAsync()
des modèles plutôt que IAsyncDisposable.DisposeAsync()
.
Par exemple, le DisposeAsync()
sera sélectionné plutôt que la méthode IAsyncEnumerator<int>.DisposeAsync()
de 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
}
Cette modification corrige une violation de spécifications où la méthode publique DisposeAsync
est visible sur le type déclaré, tandis que l’implémentation d’interface explicite n’est visible qu’à l’aide d’une référence au type d’interface.
Pour contourner cette erreur, supprimez la méthode DisposeAsync
, qui est basée sur un modèle, de votre type.
Interdire les chaînes converties en tant qu’argument par défaut
Introduit dans le Kit de développement logiciel (SDK) .NET 6.0.300, Visual Studio 2022 version 17.2. Le compilateur C# accepterait des valeurs d’argument par défaut incorrectes impliquant une conversion de référence d’une constante de chaîne et émettrait null
comme valeur constante au lieu de la valeur par défaut spécifiée dans la source. Dans Visual Studio 17.2, cela devient une erreur. Voir roslyn#59806.
Cette modification corrige une violation de spécification dans le compilateur. Les arguments par défaut doivent être des constantes de temps de compilation. Les versions précédentes ont autorisé le code suivant :
void M(IEnumerable<char> s = "hello")
La déclaration précédente nécessitait une conversion de string
à IEnumerable<char>
. Le compilateur a autorisé cette construction et émettrait null
comme valeur de l’argument. Le code précédent génère une erreur du compilateur à partir de la version 17.2.
Pour contourner cette modification, vous pouvez apporter l’une des modifications suivantes :
- Modifiez le type de paramètre afin qu’une conversion ne soit pas nécessaire.
- Modifiez la valeur de l’argument par défaut à
null
afin de restaurer le comportement précédent.
Le mot clé contextuel var
utilisé comme type de retour de lambda explicite
Introduit dans le Kit de développement logiciel (SDK) .NET 6.0.200, Visual Studio 2022 version 17.1. La var de mot clé contextuelle ne peut pas être utilisée comme type de retour lambda explicite.
Cette modification permet des fonctionnalités futures potentielles en garantissant que le var
type naturel reste le type de retour d’une expression lambda.
Vous pouvez rencontrer cette erreur si vous avez un type nommé var
et définissez une expression lambda à l’aide d’un type de retour explicite ( var
le type).
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
{
}
Les solutions de contournement incluent les modifications suivantes :
- Utilisez
@var
comme type de retour. - Supprimez le type de retour explicite afin que le compilateur détermine le type de retour.
Initialisation des gestionnaires de chaînes interpolés et de l’indexeur
Introduit dans le Kit de développement logiciel (SDK) .NET 6.0.200, Visual Studio 2022 version 17.1. Les indexeurs qui prennent un gestionnaire de chaîne interpolé et nécessitent que le récepteur en tant qu’entrée pour le constructeur ne puisse pas être utilisé dans un initialiseur d’objet.
Cette modification interdit un scénario de cas de périphérie où les initialiseurs d’indexeur utilisent un gestionnaire de chaînes interpolés et que le gestionnaire de chaînes interpolé prend le récepteur de l’indexeur en tant que paramètre du constructeur. La raison de cette modification est que ce scénario peut entraîner l’accès à des variables qui n’ont pas encore été initialisées. Prenons cet exemple :
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) {}
}
Les solutions de contournement incluent les modifications suivantes :
- Retirez le type de récepteur du gestionnaire de chaînes interpolées.
- Modifiez l’argument de l’indexeur pour qu’il soit un
string
ref, readonly ref, in, out non autorisé en tant que paramètres ou retour sur les méthodes avec des appelants non gérés uniquement
Introduit dans le Kit de développement logiciel (SDK) .NET 6.0.200, Visual Studio 2022 version 17.1.ref
/ref readonly
/in
/out
ne sont pas autorisés à être utilisés lors du retour/des paramètres d’une méthode attribuée avec UnmanagedCallersOnly
.
Cette modification est un correctif de bogue. Les valeurs de retour et les paramètres ne sont pas blittables. Le passage d’arguments ou de valeurs de retour par référence peut entraîner un comportement non défini. Aucune des déclarations suivantes ne peut être compilée :
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'.
La solution consiste à supprimer le modificateur par référence.
Longueur, nombre supposé être non négatif dans les modèles
Introduit dans le Kit de développement logiciel (SDK) .NET 6.0.200, Visual Studio 2022 version 17.1.Length
et Count
les propriétés sur les types pouvant être comptabilisés et indexables sont supposées être non négatives à des fins de sous-énumération et d’analyse exhaustive des modèles et des commutateurs.
Ces types peuvent être utilisés avec l’indexeur d’index implicite et les modèles de liste.
Les propriétés Length
et Count
, bien qu'elles soient typées comme int
, sont supposées être non négatives lors de l’analyse des modèles. Considérez cet exemple de méthode :
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
}
Avant la version 17.1, il était nécessaire de tester que le premier bras du commutateur, Count
, est négatif pour éviter un avertissement indiquant que toutes les valeurs possibles n’étaient pas couvertes. À compter de la version 17.1, le premier bras de commutateur génère une erreur du compilateur. La solution consiste à supprimer les branches switch ajoutées pour les cas non valides.
Cette modification a été apportée dans le cadre de l’ajout de modèles de liste. Les règles de traitement sont plus cohérentes si chaque utilisation d’une Length
ou Count
d’une propriété sur une collection est considérée comme non négative. Vous pouvez en savoir plus sur la modification du problème de conception de langage.
La solution consiste à supprimer les branches switch avec des conditions inaccessibles.
L’ajout d’initialiseurs de champs à un struct nécessite un constructeur explicitement déclaré
Introduit dans le Kit de développement logiciel (SDK) .NET 6.0.200, Visual Studio 2022 version 17.1.struct
Les déclarations de type avec les initialiseurs de champ doivent inclure un constructeur déclaré explicitement. En outre, tous les champs doivent être affectés définitivement dans struct
les constructeurs d’instance qui n’ont pas d’initialiseur : this()
, de sorte que les champs précédemment non attribués doivent être attribués à partir du constructeur ajouté ou des initialiseurs de champs. Voir dotnet/csharplang#5552, dotnet/roslyn#58581.
Il existe deux façons d’initialiser une variable à sa valeur par défaut en C# : new()
et default
. Pour les classes, la différence est évidente puisque new
crée une nouvelle instance et default
retourne null
. La différence est plus subtile pour les structs, car pour default
, les structs retournent une instance avec chaque champ/propriété défini sur sa propre valeur par défaut. Nous avons ajouté des initialiseurs de champs pour les structs en C# 10. Les initialiseurs de champs sont exécutés uniquement lorsqu’un constructeur déclaré explicitement s’exécute. De manière significative, ils ne s’exécutent pas lorsque vous utilisez default
ou créez un tableau de n’importe quel struct
type.
Dans la version 17.0, s'il existe des initialiseurs de champ mais qu'aucun constructeur n'est déclaré, un constructeur sans paramètre est créé pour exécuter les initialiseurs de champ. Toutefois, cela signifie que l’ajout ou la suppression d’une déclaration de constructeur peut affecter si un constructeur sans paramètre est synthétisé et, par conséquent, peut modifier le comportement de new()
.
Pour résoudre le problème, dans le Kit de développement logiciel (SDK) .NET 6.0.200 (VS 17.1), le compilateur ne synthétise plus un constructeur sans paramètre. Si un struct
contient des initialiseurs de champ et n'a pas de constructeur explicite, le compilateur génère une erreur. Si un struct
possède des initialiseurs de champ, il doit déclarer un constructeur; autrement, les initialiseurs de champ ne sont jamais exécutés.
En outre, tous les champs qui n’ont pas d’initialiseurs de champs doivent être attribués dans chaque struct
constructeur, sauf si le constructeur a un : this()
initialiseur.
Par exemple:
struct S // error CS8983: A 'struct' with field initializers must include an explicitly declared constructor.
{
int X = 1;
int Y;
}
La solution consiste à déclarer un constructeur. À moins que les champs n’aient été précédemment non attribués, ce constructeur peut, et souvent, être un constructeur sans paramètre vide :
struct S
{
int X = 1;
int Y;
public S() { Y = 0; } // ok
}
Les spécificateurs de format ne peuvent pas contenir d’accolades
Introduit dans le Kit de développement logiciel (SDK) .NET 6.0.200, Visual Studio 2022 version 17.1. Les spécificateurs de format dans des chaînes interpolées ne peuvent pas contenir d’accolades (soit {
}
). Dans les versions précédentes, {{
était interprété comme un {
échappé et }}
était interprété comme un caractère }
échappé dans le spécificateur de format. Maintenant, le premier }
caractère d’un spécificateur de format met fin à l’interpolation, et tout {
char est une erreur.
Cela rend le traitement de chaîne interpolé cohérent avec le traitement pour System.String.Format
:
using System;
Console.WriteLine($"{{{12:X}}}");
//prints now: "{C}" - not "{X}}"
X
est le format de l’hexadécimal majuscule et C
est la valeur hexadécimale pour 12.
La solution consiste à supprimer les accolades supplémentaires dans la chaîne de format.
Vous pouvez en savoir plus sur cette modification dans le problème roslyn associé.
Les types ne peuvent pas être nommés required
Introduit dans Visual Studio 2022 version 17.3. À compter de C# 11, les types ne peuvent pas être nommés required
. Le compilateur signale une erreur sur tous ces noms de types. Pour contourner ce problème, le nom du type et toutes ses utilisations doivent être échappés avec un @
:
class required {} // Error CS9029
class @required {} // No error
Cette opération a été effectuée car required
est maintenant un modificateur membre pour les propriétés et les champs.
Vous pouvez en savoir plus sur cette modification dans le problème csharplang associé.
Roslyn breaking changes