Remarque
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.
Tout au long de son historique, .NET a tenté de maintenir un niveau élevé de compatibilité entre la version et les implémentations de .NET. Bien que .NET 5 (et .NET Core) et les versions ultérieures puissent être considérés comme une nouvelle technologie par rapport à .NET Framework, deux facteurs majeurs limitent la capacité de cette implémentation de .NET à différer de .NET Framework :
- Un grand nombre de développeurs ont initialement développé ou continuent de développer des applications .NET Framework. Ils s’attendent à un comportement cohérent entre les implémentations .NET.
- .NET projets de bibliothèque standard permettent aux développeurs de créer des bibliothèques qui ciblent des API communes partagées par .NET Framework et .NET 5 (et .NET Core) et versions ultérieures. Les développeurs s’attendent à ce qu’une bibliothèque utilisée dans une application .NET se comporte de la même façon que celle utilisée dans une application .NET Framework.
En plus de la compatibilité entre les implémentations .NET, les développeurs s’attendent à un niveau élevé de compatibilité entre les versions d’une implémentation donnée de .NET. En particulier, le code écrit pour une version antérieure de .NET Core doit s’exécuter en toute transparence sur .NET 5 ou une version ultérieure. En fait, de nombreux développeurs s’attendent à ce que les nouvelles API trouvées dans les nouvelles versions de .NET soient également compatibles avec les versions de préversion dans lesquelles ces API ont été introduites.
Cet article décrit les modifications qui affectent la compatibilité et la façon dont l’équipe .NET évalue chaque type de modification. Comprendre comment l’équipe .NET aborde les changements ayant des ruptures potentielles est particulièrement utile pour les développeurs qui ouvrent des pull requests modifiant le comportement des API existantes dans .NET.
Les sections suivantes décrivent les catégories de modifications apportées aux API .NET et leur impact sur la compatibilité des applications. Les modifications sont autorisées (✔️), non autorisées (❌), ou nécessitent un jugement et une évaluation de la façon dont le comportement précédent était prévisible, évident et cohérent(❓).
Remarque
- Outre la façon dont les modifications apportées aux bibliothèques .NET sont évaluées, les développeurs de bibliothèques peuvent également utiliser ces critères pour évaluer les modifications apportées à leurs bibliothèques ciblant plusieurs implémentations et versions de .NET.
- Pour plus d’informations sur les catégories de compatibilité, par exemple, la compatibilité ascendante et descendante, consultez Comment les modifications de code peuvent affecter la compatibilité.
Modifications apportées au contrat public
Les modifications apportées à cette catégorie modifient la surface d’exposition publique d’un type. La plupart des modifications de cette catégorie ne sont pas autorisées, car elles violent la compatibilité descendante (la capacité d’une application développée avec une version précédente d’une API à exécuter sans recompilation sur une version ultérieure).
Les types
✔️ AUTORISÉ : suppression d’une implémentation d’interface d’un type lorsque l’interface est déjà implémentée par un type de base
❓ NÉCESSITE JUGEMENT : Ajout d’une nouvelle implémentation d’interface à un type
Il s’agit d’un changement acceptable, car il n’affecte pas les clients existants. Toutes les modifications apportées au type doivent fonctionner dans les limites des modifications acceptables définies ici pour que la nouvelle implémentation reste acceptable. La prudence extrême est nécessaire lors de l’ajout d’interfaces qui affectent directement la capacité d’un concepteur ou d’un sérialiseur à générer du code ou des données qui ne peuvent pas être consommées de bas niveau. Par exemple, l’interface ISerializable .
❓ EXIGE LE JUGEMENT : Présentation d’une nouvelle classe de base
Un type peut être introduit dans une hiérarchie entre deux types existants s’il n’introduit aucun nouveau membre abstrait ni modifier la sémantique ou le comportement des types existants. Par exemple, dans .NET Framework 2.0, la classe DbConnection est devenue une nouvelle classe de base pour SqlConnection, qui avait précédemment dérivé directement de Component.
✔️ AUTORISÉ : déplacement d’un type d’un assembly à un autre
L’ancien assemblage doit être marqué avec celle TypeForwardedToAttribute pointant vers le nouvel assemblage.
✔️ AUTORISÉ : changement d’un type struct en type
readonly structLa modification d’un
readonly structtype en typestructn’est pas autorisée.✔️ ALLOWED : Ajout du mot clé sealed ou abstract à un type lorsqu’il n’existe aucun constructeur accessible (public ou protégé)
✔️ AUTORISÉ : Extension de la visibilité d’un type
❌ NON AUTORISÉ : changement de l’espace de noms ou du nom d’un type
❌ NON AUTORISÉ : changement du nom ou suppression d’un type public
Cela interrompt tout le code qui utilise le type renommé ou supprimé.
Remarque
Dans de rares cas, .NET peut supprimer une API publique. Pour plus d’informations, consultez la suppression de l’API dans .NET. Pour plus d'informations sur la stratégie de support de .NET, consultez .NET Stratégie de support.
❌ DISALLOWED : Modification du type sous-jacent d’une énumération
Il s’agit d’un changement cassant au niveau de la compilation et du comportement ainsi qu’un changement cassant binaire qui peut rendre les arguments d’attribut non analysables.
❌ INTERDIT : Sceller un type qui n'était pas scellé auparavant
❌ DISALLOWED : Ajout d’une interface à l’ensemble de types de base d’une interface
Si une interface implémente une interface qu’elle n’a pas implémentée précédemment, tous les types qui ont implémenté la version d’origine de l’interface sont rompus.
❓ NÉCESSITE JUGEMENT : Suppression d’une classe de l’ensemble de classes de base ou d’une interface de l’ensemble d’interfaces implémentées
Il existe une exception à la règle de suppression d’interface : vous pouvez ajouter l’implémentation d’une interface qui dérive de l’interface supprimée. Par exemple, vous pouvez supprimer IDisposable si le type ou l’interface implémente maintenant IComponent, qui implémente IDisposable.
❌ NON AUTORISÉ : changement d’un
readonly structtype en type structToutefois, la modification d'un type
structen un typereadonly structest autorisée.❌ INTERDIT : Modification d’un type struct en type
ref struct, et vice versa❌ NON AUTORISÉ : réduction de la visibilité d’un type
Toutefois, l’augmentation de la visibilité d’une catégorie est autorisée.
Membres
✔️ AUTORISÉ : Extension de la visibilité d’un membre qui n’est pas virtuel
✔️ AUTORISÉ : Ajout d’un membre abstrait à un type public qui n’a aucun constructeur accessible (public ou protégé), ou le type est scellé
Cependant, ajouter un membre abstrait à un type qui a des constructeurs accessibles (publics ou protégés) et n'est pas
sealedn'est pas autorisé.✔️ AUTORISÉ : restriction de la visibilité d’un membre protégé lorsque le type n’a aucun constructeur accessible (public ou protégé) ou que le type est scellé
✔️ AUTORISÉ : déplacement d’un membre vers une classe supérieure au type à partir duquel il a été supprimé dans la hiérarchie
✔️ AUTORISÉ : ajout ou suppression d’une substitution
L’ajout d’une substitution, les consommateurs précédents pourraient ignorer la substitution lors de l’appel de base.
✔️ ALLOWED : Ajout d’un constructeur à une classe, ainsi qu’un constructeur sans paramètre si la classe n’avait précédemment aucun constructeur
Toutefois, l’ajout d’un constructeur à une classe qui n’avait précédemment aucun constructeur sans ajouter le constructeur sans paramètre n’est pas autorisé.
✔️ AUTORISÉ : Passage d’une
ref readonlyvaleur de retour à unerefvaleur de retour (à l’exception des méthodes ou interfaces virtuelles)✔️ AUTORISÉ : Suppression de readonly d’un champ, sauf si le type statique du champ est un type de valeur mutable
✔️ AUTORISÉ : Appel d’un nouvel événement qui n’a pas été défini précédemment
❓ NÉCESSITE UN JUGEMENT : Ajout d’un nouveau champ d’instance à un type
Cette modification a un impact sur la sérialisation.
❌ NON AUTORISÉ : changement de nom ou suppression d’un paramètre ou membre public
Cela interrompt tout le code qui utilise le membre renommé ou supprimé ou le paramètre.
Cela inclut la suppression et le changement de nom d’un accesseur Get ou Set à partir d’une propriété, ou de membres d’une énumération.
❓ NÉCESSITE UN JUGEMENT : Ajout d’un membre à une interface
Bien qu'il s'agit d'un changement cassant dans le sens où il élève votre version minimale de .NET à .NET Core 3.0 (C# 8.0), c'est-à-dire lorsque les membres de l'interface default (DIMs) ont été introduits, l'ajout d'un membre statique, non abstrait et non virtuel à une interface est autorisé.
Si vous fournissez une implémentation, l’ajout d’un nouveau membre à une interface existante n’entraîne pas nécessairement des échecs de compilation dans les assemblys en aval. Toutefois, toutes les langues ne prennent pas en charge les DIMs. En outre, dans certains scénarios, le runtime ne peut pas décider quel membre d’interface par défaut appeler. À compter de C# 13,
ref structles types peuvent implémenter des interfaces, mais ils ne peuvent pas être boxés ou convertis en type d’interface. Par conséquent, unref structtype doit fournir une implémentation explicite pour chaque membre de l’interface d’instance. Il ne peut donc pas utiliser l’implémentation par défaut fournie par l’interface. L'ajout d'un membre d'instance par défaut à une interface qu'unref structimplémente nécessite que leref structajoute une implémentation correspondante, ce qui constitue une modification entraînant une rupture de compatibilité. Pour ces raisons, utilisez le jugement lors de l’ajout d’un membre à une interface existante.Remarque
Si votre interface est implémentée par des types
ref struct(possible en C# 13 et versions ultérieures), ajouter un membre d’instance par défaut à l’interface constitue un changement radical au niveau du code source pour les codes qui appellent l'interface. Ilref structdoit fournir une implémentation explicite du nouveau membre ; il ne peut pas revenir à l’implémentation par défaut.❌ NON AUTORISÉ : modification de la valeur d’un membre d’énumération ou d’une constante publique
❌ DISALLOWED : Modification du type d’une propriété, d’un champ, d’un paramètre ou d’une valeur de retour
❌ DISALLOWED : Ajout, suppression ou modification de l’ordre des paramètres
❌ NON AUTORISÉ : ajout ou suppression des mots clés in, out, ou ref dans un paramètre
✔️ AUTORISÉ : modification d’un
refparamètre enref readonlyLa modification d’un paramètre de
refàref readonlyest compatible avec le code source pour les sites d’appel existants qui utilisent des arguments avec le modificateurref. Ces appels continuent de se compiler sans changement. Contrairement à la modification derefenin, un paramètreref readonlyn’autorise pas silencieusement les appelants à passer des *rvalues* (non variables) ; le compilateur émet un avertissement si l’argument n’est pas une variable. Les sites d’appel existantsrefrestent valides.❌ NON AUTORISÉ : Modification de
inparamètre enref readonlyLes sites d'appel qui passent des arguments
insans le modificateurin(que le compilateur autorise pour les paramètresin) recevront un avertissement lorsque le paramètre est modifié enref readonly, carref readonlynécessite que l'argument soit transmis par référence. Les appelants qui traitent les avertissements comme des erreurs subissent une modification cassant la source.❌ NON AUTORISÉ : changement de nom d’un paramètre (y compris changement de casse)
Cela est considéré comme un changement cassant pour deux raisons :
Cela empêche les scénarios à liaison tardive comme la fonctionnalité de liaison tardive de Visual Basic et dynamic de C#.
Il interrompt la compatibilité de la source lorsque les développeurs utilisent des arguments nommés.
❌ INTERDIT: Passage d’une
refvaleur de retour à uneref readonlyvaleur de retour❌️ INTERDIT : Passer d'une
ref readonlyà unerefvaleur de retour pour une méthode virtuelle ou une interface❌ NON AUTORISÉ : ajout ou suppression de abstract d'un membre
❌ NON AUTORISÉ : suppression du mot clé virtual d'un membre
❌ NON AUTORISÉ : ajout du mot clé virtual à un membre
Bien qu’il ne s’agit souvent pas d’un changement cassant, car le compilateur C# a tendance à émettre des instructions il ( callvirt Intermediate Language) pour appeler des méthodes non virtuelles (
callvirteffectue une vérification null, alors qu’un appel normal ne le fait pas), ce comportement n’est pas invariable pour plusieurs raisons :- C# n'est pas le seul langage que .NET vise.
- Le compilateur C# tente de plus en plus d’optimiser
callvirtvers un appel normal chaque fois que la méthode cible n’est pas virtuelle et n’est probablement pas null (par exemple, une méthode accessible via l’opérateur de propagation null).
Rendre une méthode virtuelle signifie que le code consommateur finirait souvent par l’appeler de façon non virtuelle.
❌ NON AUTORISÉ : changement d’un membre virtuel en abstrait
Un membre virtuel fournit une implémentation de méthode qui peut être substituée par une classe dérivée. Un membre abstrait ne fournit aucune implémentation et doit être substitué.
❌ INTERDIT : Ajout du mot clé sealed à un membre d’interface
L’ajout
sealedà un membre d’interface par défaut le rend non virtuel, empêchant l’implémentation d’un type dérivé de ce membre d’être appelé.❌ NON AUTORISÉ : ajout d’un membre abstrait à un type public qui a des constructeurs (publics ou protégés) accessibles et qui n’est pas sealed
❌ NON AUTORISÉ : ajout ou suppression du mot clé static d'un membre
❌ NON AUTORISÉ : ajout d’une surcharge qui exclut une surcharge existante et définit un comportement différent
Cela perturbe les clients existants qui étaient dépendants de la surcharge précédente. Par exemple, si une classe a une seule version d’une méthode qui accepte un UInt32, un consommateur existant est correctement lié à cette surcharge lors du passage d’une valeur Int32. Toutefois, si vous ajoutez une surcharge qui accepte un Int32, lors de la recompilation ou de l’utilisation de liaison tardive, le compilateur se lie désormais à la nouvelle surcharge. Si un comportement différent se produit, il peut s’agir d’un changement cassant.
❓ REQUIERT JUGEMENT : Ajout OverloadResolutionPriorityAttribute à une surcharge existante ou modification de sa valeur de priorité
L’élément OverloadResolutionPriorityAttribute influe sur la résolution de surcharge au niveau de la source : les appelants qui recompilent peuvent choisir une surcharge différente de celle d’avant. L’utilisation prévue consiste à ajouter l’attribut à une nouvelle surcharge, meilleure afin que le compilateur le préfère sur les éléments existants. L’ajout à une surcharge existante ou la modification de la valeur de priorité sur une surcharge déjà attribuée peut être un changement cassant source, car les appelants qui recompilent peuvent changer de comportement.
✔️ AUTORISÉ : Ajout de la contrainte de type anti-
allows ref structà un paramètre de type génériqueL’ajout
allows ref structdéveloppe les types qui peuvent être utilisés en tant qu’arguments de type en autorisant lesref structtypes. Les appelants existants utilisant des arguments non deref structtype ne sont pas affectés. La méthode ou le type générique doit respecter les règles de sécurité ref pour toutes les instances de ce paramètre de type.❌ DISALLOWED : Suppression de la
allows ref structcontrainte anti-contrainte d’un paramètre de type génériqueallows ref structLa suppression limite les types que les appelants peuvent utiliser comme arguments de type. Tous les appels qui passent unref structen tant qu'argument de type ne se compileront plus.❌ NON AUTORISÉ : ajout d’un constructeur à une classe qui n’avait auparavant pas de constructeur sans ajout du constructeur sans paramètre
❌️ NON AUTORISÉ : ajout de readonly à un champ
❌ INTERDIT : Réduction de la visibilité d’un membre
Cela inclut la réduction de la visibilité d’un membre protégé lorsqu’il existe des constructeurs accessibles (
publicouprotected) et que le type n’est passcellé. Si ce n’est pas le cas, réduire la visibilité d’un membre protégé est possible.L’augmentation de la visibilité d’un membre est autorisée.
❌ NON AUTORISÉ : modification du type d’un membre
La valeur de retour d’une méthode ou du type d’une propriété ou d’un champ ne peut pas être modifiée. Par exemple, la signature d’une méthode qui retourne une Object valeur ne peut pas être modifiée pour retourner un String, ou inversement.
❌ INTERDIT : Ajout d’un champ d’instance à une structure sans champs non publics
Si une structure n’a que des champs publics ou n’a pas de champs du tout, les appelants peuvent déclarer des variables locales de ce type de structure sans appeler le constructeur de la structure ou initialiser la variable locale à
default(T), tant que tous les champs publics sont définis dans la structure avant la première utilisation. L’ajout de nouveaux champs publics ou non publics à un tel struct constitue une modification de rupture de code source pour ces appels, car le compilateur exigera désormais que les champs supplémentaires soient initialisés.En outre, l'ajout de nouveaux champs, qu'ils soient publics ou non publics, à une structure sans champs ou avec seulement des champs publics constitue un changement binaire perturbateur pour les appelants qui ont appliqué
[SkipLocalsInit]à leur code. Étant donné que le compilateur ne connaît pas ces champs au moment de la compilation, il peut émettre de l'IL qui n'initialise pas entièrement la structure, ce qui entraîne la création de la structure à partir de données de pousse non initialisées.Si un struct a des champs non publics, le compilateur applique déjà l’initialisation via le constructeur ou
default(T), et l’ajout de nouveaux champs d’instance n’est pas un changement cassant.❌ NON AUTORISÉ : déclenchement d’un événement existant alors qu’il n’a jamais été déclenché auparavant
Changements comportementaux
Assemblages
✔️ AUTORISÉ : rendre un assembly portable lorsque les mêmes plateformes sont toujours prises en charge
❌ INTERDIT : Modification du nom d’un assemblage
❌ NON AUTORISÉ : modification de la clé publique d’un assembly
Propriétés, champs, paramètres et valeurs de retour
✔️ AUTORISÉ : Modification de la valeur d’une propriété, d’un champ, d’une valeur de retour ou d’un paramètre sortant en type plus dérivé
Par exemple, une méthode qui retourne un type de Object peut retourner une String instance. (Toutefois, la signature de méthode ne peut pas changer.)
✔️ AUTORISÉ : augmentation de la plage de valeurs acceptées pour une propriété ou un paramètre si le membre n’est pas virtuel
Bien que la plage de valeurs qui peuvent être passées à la méthode ou retournées par le membre puisse se développer, le paramètre ou le type de membre ne peut pas. Par exemple, alors que les valeurs passées à une méthode peuvent passer de 0-124 à 0-255, le type de paramètre ne peut pas passer de Byte à Int32.
❌ DISALLOWED : Augmenter la plage de valeurs acceptables pour une propriété ou un paramètre lorsque le membre est virtuel
Ce changement empêche le fonctionnement des membres substitués existants, qui ne fonctionneront pas correctement pour la plage de valeurs étendue.
❌ INTERDIT : Réduction de la plage de valeurs acceptées pour une propriété ou un paramètre
❌ INTERDIT : Augmentation de la plage de valeurs retournées pour une propriété, un champ, une valeur de retour ou un paramètre out
❌ NON AUTORISÉ : modification des valeurs renvoyées pour une propriété, un champ, une valeur de retour de méthode ou un paramètre out
❌ DISALLOWED : Modification de la valeur par défaut d’une propriété, d’un champ ou d’un paramètre
La modification ou la suppression de la valeur par défaut d’un paramètre n’entraîne pas de rupture de compatibilité binaire. La suppression d’une valeur par défaut de paramètre est un saut source et la modification d’une valeur par défaut de paramètre peut entraîner un arrêt comportemental après la recompilation.
Pour cette raison, la suppression des valeurs par défaut des paramètres est acceptable dans le cas spécifique de « déplacement » de ces valeurs par défaut vers une nouvelle surcharge de méthode pour éliminer l’ambiguïté. Par exemple, considérez une méthode
MyMethod(int a = 1)existante . Si vous introduisez une surcharge deMyMethodavec deux paramètres facultatifsaetb, vous pouvez conserver la compatibilité en déplaçant la valeur par défaut deavers la nouvelle surcharge. Désormais, les deux surcharges sontMyMethod(int a)etMyMethod(int a = 1, int b = 2). Ce modèle permet àMyMethod()de compiler.❌ DISALLOWED : Modification de la précision d’une valeur de retour numérique
❓ EXIGER LE JUGEMENT : Modification de l’analyse des entrées et levée de nouvelles exceptions (même si le comportement d’analyse n’est pas spécifié dans la documentation)
❌ INTERDIT : ajouter ou supprimer des types de cas dans une déclaration de
unionL’ajout ou la suppression d’un type de cas à partir d'un type
unionest à la fois une rupture binaire et une rupture de code source.Les tests de correspondance de modèles ne sont plus exhaustifs après l’ajout d’un type de cas. Le compilateur signale les expressions de correspondance de motifs comme non exhaustives. Au moment de l’exécution, les valeurs inattendues provoquent des exceptions d’exécution. La suppression d’un type de cas supprime la déclaration du constructeur pour ce type de cas.
Exceptions
✔️ AUTORISÉ : lever une exception plus spécifique qu’une exception existante
Étant donné que la nouvelle exception est une sous-classe d’une exception existante, le code de gestion des exceptions précédent continue de gérer l’exception. Par exemple, dans .NET Framework 4, les méthodes de création et de récupération de culture ont commencé à lever un CultureNotFoundException au lieu d’un ArgumentException si la culture est introuvable. Parce que CultureNotFoundException dérive de ArgumentException, il s’agit d’un changement acceptable.
✔️ AUTORISÉ : levée d’une exception plus spécifique que NotSupportedException, NotImplementedException, NullReferenceException
✔️ AUTORISÉ : lancer une exception considérée comme irrécupérable
Les exceptions irrécupérables ne doivent pas être interceptées, mais doivent plutôt être gérées par un gestionnaire global de haut niveau. Par conséquent, les utilisateurs ne sont pas censés avoir du code qui intercepte ces exceptions explicites. Les exceptions irrécupérables sont les suivantes :
✔️ AUTORISÉ : levée une exception dans un nouveau chemin de code
L’exception ne doit s’appliquer qu’à un nouveau chemin d’accès de code exécuté avec de nouvelles valeurs de paramètre ou d’état et qui ne peut pas être exécuté par le code existant qui cible la version précédente.
✔️ AUTORISÉ : suppression d’une exception pour activer un comportement plus robuste ou de nouveaux scénarios
Par exemple, une méthode
Dividequi pouvait auparavant uniquement gérer des valeurs positives et levait un ArgumentOutOfRangeException peut être modifiée pour prendre en charge les valeurs positives et négatives sans lever d’exception.✔️ AUTORISÉ : modification du texte d’un message d’erreur
Les développeurs ne doivent pas s’appuyer sur le texte des messages d’erreur, qui changent également en fonction de la culture de l’utilisateur.
❌ NON AUTORISÉ : levée d’une exception dans tous les autres cas non répertoriés ci-dessus
❌ NON AUTORISÉ : suppression d’une exception dans tous les autres cas non répertoriés ci-dessus
Attributs
✔️ AUTORISÉ : modification de la valeur d’un attribut qui n’est pas observable
❌ DISALLOWED : Modification de la valeur d’un attribut observable
❓ NÉCESSITE UN JUGEMENT : Suppression d’un attribut
Dans la plupart des cas, la suppression d’un attribut (par exemple NonSerializedAttribute) est un changement cassant.
Support de la plateforme
✔️ AUTORISÉ : Prise en charge d’une opération sur une plateforme qui n’était pas prise en charge précédemment
❌ NON AUTORISÉ : cesser la prise en charge ou commencer à requérir un service pack spécifique pour une opération qui était précédemment prise en charge sur une plateforme
Modifications de l’implémentation interne
❓ NÉCESSITE UN JUGEMENT : modification de la surface d’un type interne
Ces modifications sont généralement autorisées, bien qu’elles interrompent la réflexion privée. Dans certains cas, où les bibliothèques tierces populaires ou un grand nombre de développeurs dépendent des API internes, ces modifications peuvent ne pas être autorisées.
❓ NÉCESSITE UN JUGEMENT : modification de l’implémentation interne d’un membre
Ces modifications sont généralement autorisées, bien qu’elles interrompent la réflexion privée. Dans certains cas, lorsque le code client dépend fréquemment de la réflexion privée ou de l’endroit où la modification introduit des effets secondaires inattendus, ces modifications peuvent ne pas être autorisées.
✔️ AUTORISÉ : Amélioration des performances d’une opération
La possibilité de modifier les performances d’une opération est essentielle, mais ces modifications peuvent interrompre le code qui repose sur la vitesse actuelle d’une opération. Cela est particulièrement vrai du code qui dépend du minutage des opérations asynchrones. La modification des performances ne doit pas avoir d’effet sur d’autres comportements de l’API en question ; sinon, la modification pourrait entraîner une rupture.
✔️ AUTORISÉ : Changer indirectement (et souvent négativement) les performances d’une opération
Si le changement en question n’est pas classé comme une rupture pour une autre raison, c’est acceptable. Souvent, des actions doivent être effectuées qui peuvent inclure des opérations supplémentaires ou ajouter de nouvelles fonctionnalités. Cela affecte presque toujours les performances, mais peut être essentiel pour rendre l’API en question fonction comme prévu.
❌ DISALLOWED : Modification d’une API synchrone en api asynchrone (et inversement)
Modifications du code
✔️ AUTORISÉ : ajout de params à un paramètre
❌ INTERDIT : Modification d’un struct en d'une classe et inversement
❌ NON AUTORISÉ : ajout de l'instruction checked à un bloc de code
Cette modification pourrait pousser le code précédemment exécuté à lever un OverflowException, ce qui n’est pas acceptable.
❌ NON AUTORISÉ : suppression de params à partir d’un paramètre
❌ INTERDIT : Modification du type de collection d’un
paramsparamètreÀ compter de C# 13,
paramsles paramètres prennent en charge les types de collection non matricielles, y compris Span<T>, les types de ReadOnlySpan<T> struct ou de classe qui implémentent IEnumerable<T> avec un constructeur sans paramètre accessible et une méthode d’instanceAdd, ainsi que des types d’interface spécifiques tels que IList<T>. La modification du type de collection d’un paramètre existantparams(par exemple, le passage deparams T[]àparams ReadOnlySpan<T>) modifie la signature IL de la méthode et constitue une rupture binaire. Les appelants compilés avec la version précédente doivent être recompilés.✔️ ALLOWED : Conversion d’une méthode d’extension en syntaxe de membre de bloc d’extension
À compter de C# 14, vous pouvez déclarer des membres d’extension à l’aide de blocs
extensionen plus de l’ancienne syntaxe à paramètresthis. Les deux formulaires génèrent un il identique, de sorte que les appelants ne peuvent pas faire la distinction entre eux. La conversion des méthodes d’extension existantes en nouvelle syntaxe de bloc d’extension est binaire et compatible avec la source.❌ NON AUTORISÉ : modification de l’ordre dans lequel les événements sont déclenchés
Les développeurs peuvent raisonnablement s’attendre à ce que les événements se déclenchent dans le même ordre, et le code du développeur dépend fréquemment de l’ordre dans lequel les événements sont déclenchés.
❌ NON AUTORISÉ : suppression du déclenchement d’un événement sur une action donnée
❌ INTERDIT : Modifier le nombre de fois où les événements donnés sont appelés
❌ INTERDIT : Ajout du FlagsAttribute à un type d’énumération