Regels voor compatibiliteit wijzigen

In de loop van de geschiedenis heeft .NET geprobeerd een hoog compatibiliteitsniveau van versie tot versie en implementaties van .NET te handhaven. Hoewel .NET 5 (en .NET Core) en latere versies kunnen worden beschouwd als een nieuwe technologie in vergelijking met .NET Framework, beperken twee belangrijke factoren de mogelijkheid van deze implementatie van .NET om af te wijken van .NET Framework:

  • Een groot aantal ontwikkelaars is oorspronkelijk ontwikkeld of blijft .NET Framework-toepassingen ontwikkelen. Ze verwachten consistent gedrag in .NET implementaties.
  • met .NET Standard-bibliotheekprojecten kunnen ontwikkelaars bibliotheken maken die gericht zijn op algemene API's die worden gedeeld door .NET Framework en .NET 5 (en .NET Core) en latere versies. Ontwikkelaars verwachten dat een bibliotheek die wordt gebruikt in een .NET-toepassing zich identiek moet gedragen aan dezelfde bibliotheek die wordt gebruikt in een .NET Framework-toepassing.

Naast compatibiliteit in .NET implementaties verwachten ontwikkelaars een hoog compatibiliteitsniveau in verschillende versies van een bepaalde implementatie van .NET. Code die is geschreven voor een eerdere versie van .NET Core, moet met name naadloos worden uitgevoerd op .NET 5 of een latere versie. Veel ontwikkelaars verwachten zelfs dat de nieuwe API's in nieuw uitgebrachte versies van .NET ook compatibel moeten zijn met de pre-releaseversies waarin deze API's zijn geïntroduceerd.

In dit artikel worden wijzigingen beschreven die van invloed zijn op de compatibiliteit en de manier waarop het .NET team elk type wijziging evalueert. Begrijpen hoe het .NET team mogelijke belangrijke wijzigingen nadert, is met name handig voor ontwikkelaars die pull-aanvragen openen die het gedrag van bestaande .NET API's wijzigen.

In de volgende secties worden de categorieën beschreven van wijzigingen die zijn aangebracht in .NET API's en de invloed ervan op toepassingscompatibiliteit. Wijzigingen zijn toegestaan (✔️), niet toegestaan (❌), of vereisen beoordeling en een evaluatie van hoe voorspelbaar, duidelijk en consistent het vorige gedrag was (❓).

Opmerking

  • Naast de wijze waarop wijzigingen in .NET bibliotheken worden geëvalueerd, kunnen bibliotheekontwikkelaars deze criteria ook gebruiken om wijzigingen in hun bibliotheken te evalueren die gericht zijn op meerdere .NET implementaties en versies.
  • Zie Hoe codewijzigingen van invloed kunnen zijn op de compatibiliteit voor informatie over de compatibiliteitscategorieën, zoals voorwaartse en achterwaartse compatibiliteit.

Wijzigingen in het overheidscontract

Wijzigingen in deze categorie wijzigen het openbare oppervlak van een type. De meeste wijzigingen in deze categorie zijn niet toegestaan omdat ze compatibiliteit met eerdere versies schenden (de mogelijkheid van een toepassing die is ontwikkeld met een eerdere versie van een API om uit te voeren zonder opnieuw te compileren op een latere versie).

Typen

  • ✔️ TOEGESTAAN: Een interface-implementatie van een type verwijderen wanneer de interface al door een basistype wordt geïmplementeerd

  • Vraagt om beoordeling: een nieuwe interface-implementatie toevoegen aan een type

    Dit is een acceptabele wijziging omdat deze geen nadelige invloed heeft op bestaande clients. Wijzigingen in het type moeten binnen de grenzen van acceptabele wijzigingen werken die hier zijn gedefinieerd, zodat de nieuwe implementatie acceptabel blijft. Extreme voorzichtigheid is nodig bij het toevoegen van interfaces die rechtstreeks van invloed zijn op de mogelijkheid van een ontwerper of serializer om code of gegevens te genereren die niet op down-level kunnen worden gebruikt. Een voorbeeld is de ISerializable interface.

  • Vereist beoordeling: Het introduceren van een nieuwe basisklasse

    Een type kan worden geïntroduceerd in een hiërarchie tussen twee bestaande typen als het geen nieuwe abstracte leden introduceert of de semantiek of het gedrag van bestaande typen wijzigt. In .NET Framework 2.0 werd de klasse DbConnection bijvoorbeeld een nieuwe basisklasse voor SqlConnection, die eerder rechtstreeks was afgeleid van Component.

  • ✔️ TOEGESTAAN: Een type van de ene assemblage naar de andere verplaatsen

    De oude assembly moet worden gemarkeerd met de TypeForwardedToAttribute aanduiding die naar de nieuwe assembly verwijst.

  • ✔️ TOEGESTAAN: Het wijzigen van een struct-type naar een readonly struct-type

    Het wijzigen van een readonly struct type in een struct type is niet toegestaan.

  • ✔️ TOEGESTAAN: Het verzegelde of abstracte trefwoord toevoegen aan een type wanneer er geen toegankelijke (openbare of beveiligde) constructors zijn

  • ✔️ TOEGESTAAN: De zichtbaarheid van een type uitbreiden

  • NIET TOEGESTAAN: het wijzigen van de namespace of naam van een type

  • NIET TOEGESTAAN: de naam van een openbaar type wijzigen of verwijderen

    Hiermee wordt alle code die het hernoemde of verwijderde type gebruikt, verbroken.

    Opmerking

    In zeldzame gevallen kan .NET een openbare API verwijderen. Zie API verwijderen in .NET voor meer informatie. Zie .NET Ondersteuningsbeleid voor meer informatie over het ondersteuningsbeleid van .NET.

  • NIET TOEGESTAAN: Het wijzigen van het onderliggende type van een opsomming

    Dit is een ingrijpende verandering in compileertijd en gedrag evenals een binaire breuk die kenmerkargumenten niet meer te verwerken kan maken.

  • NIET TOEGESTAAN: Een type verzegelen dat eerder niet was verzegeld

  • NIET TOEGESTAAN: Een interface toevoegen aan de verzameling basistypen van een interface

    Als een interface een interface implementeert die eerder niet is geïmplementeerd, worden alle typen die de oorspronkelijke versie van de interface hebben geïmplementeerd, verbroken.

  • VEREIST OORDEEL: Een klasse verwijderen uit de set basisklassen of een interface uit de set geïmplementeerde interfaces

    Er is één uitzondering op de regel voor het verwijderen van de interface: u kunt de implementatie van een interface die is afgeleid van de verwijderde interface toevoegen. U kunt bijvoorbeeld IDisposable verwijderen als het type of de interface nu IComponent implementeert, die IDisposable implementeert.

  • NIET TOEGESTAAN: een readonly struct type wijzigen in een struct type

    De wijziging van een struct type in een readonly struct type is echter toegestaan.

  • NIET TOEGESTAAN: een struct type wijzigen in een ref struct type en omgekeerd

  • NIET TOEGESTAAN: De zichtbaarheid van een type beperken

    Het vergroten van de zichtbaarheid van een type is echter toegestaan.

Leden

  • ✔️ TOEGESTAAN: De zichtbaarheid van een lid uitbreiden dat niet virtueel is

  • ✔️ TOEGESTAAN: Een abstract lid toevoegen aan een publiekelijk type dat geen toegankelijke (openbare of beschermde) constructors heeft, of het type is ondertekend

    Het is niet toegestaan om een abstract lid toe te voegen aan een type dat toegankelijke (openbare of beveiligde) constructors heeft en dat niet sealed is.

  • ✔️ TOEGESTAAN: De zichtbaarheid van een beveiligd lid beperken wanneer het type geen toegankelijke (openbare of beveiligde) constructors heeft of het type is verzegeld

  • ✔️ TOEGESTAAN: Een lid verplaatsen naar een klasse hoger in de hiërarchie dan het type waaruit het is verwijderd

  • ✔️ TOEGESTAAN: Een override toevoegen of verwijderen

    Als u een overschrijving introduceert, kunnen eerdere consumenten voorbijgaan aan de overschrijving bij het aanroepen van basis.

  • ✔️ TOEGESTAAN: Een constructor toevoegen aan een klasse, samen met een parameterloze constructor als de klasse eerder geen constructors had

    Het toevoegen van een constructor aan een klasse die eerder geen constructors had zonder de parameterloze constructor toe te voegen, is echter niet toegestaan.

  • ✔️ TOEGESTAAN: Een lid wijzigen van abstract naar virtueel

  • ✔️ TOEGESTAAN: Van een ref readonly naar een ref retourwaarde wijzigen (met uitzondering van virtuele methoden of interfaces)

  • ✔️ TOEGESTAAN: readonly uit een veld verwijderen, tenzij het statische type van het veld een veranderbaar waardetype is

  • ✔️ TOEGESTAAN: Een nieuwe gebeurtenis aanroepen die niet eerder is gedefinieerd

  • VEREIST BEOORDELING: een nieuw exemplaarveld toevoegen aan een type

    Deze wijziging heeft invloed op serialisatie.

  • NIET TOEGESTAAN: een openbaar lid of parameter hernoemen of verwijderen

    Dit verbreekt alle code die gebruikmaakt van het hernoemde of verwijderde lid of parameter.

    Dit omvat het verwijderen of wijzigen van de naam van een getter of setter uit een eigenschap, evenals het wijzigen of verwijderen van opsommingsleden.

  • VEREIST OORDEEL: Een lid toevoegen aan een interface

    Hoewel het een belangrijke wijziging is in de zin dat uw minimale .NET-versie wordt verhoogd naar .NET Core 3.0 (C# 8.0), dat was toen default interfaceleden (DIM's) werden geïntroduceerd, is het toegestaan om een statisch, niet-abstract, en niet-virtueel lid aan een interface toe te voegen.

    Als u een implementatie opgeeft, leidt het toevoegen van een nieuw lid aan een bestaande interface niet noodzakelijkerwijs tot compilatiefouten in downstreamassembly's. Niet alle talen ondersteunen echter DIM's. In sommige scenario's kan de runtime ook niet bepalen welk standaardinterfacelid moet worden aangeroepen. Vanaf C# 13 kunnen ref struct typen interfaces implementeren, maar ze kunnen niet geboxed of geconverteerd worden naar een interfacetype. Daarom moet een ref struct type een expliciete implementatie bieden voor elk lid van de instantieinterface. Het kan dus niet gebruikmaken van de standaard implementatie die door de interface wordt geleverd. Als u een standaard instantiëlid toevoegt aan een interface die door een ref struct wordt geïmplementeerd, vereist dit dat ref struct een bijbehorende implementatie toevoegt, wat een bronbrekende wijziging is. Gebruik om deze redenen een oordeel bij het toevoegen van een lid aan een bestaande interface.

    Opmerking

    Als uw interface wordt geïmplementeerd door ref struct types (mogelijk in C# 13 en hoger), is het toevoegen van een standaardinstantie-lid aan de interface een brekende wijziging in de broncode voor deze aanroepers. Het ref struct moet een expliciete implementatie van het nieuwe lid bieden. Het kan niet terugvallen op de standaard implementatie.

  • NIET TOEGESTAAN: Het wijzigen van de waarde van een openbare constante of opsommingslid

  • NIET TOEGESTAAN: het wijzigen van het type van een eigenschap, veld, parameter of retourwaarde

  • NIET TOEGESTAAN: Parameters toevoegen, verwijderen of de volgorde wijzigen

  • NIET TOEGESTAAN: het trefwoord in, uit of ref aan een parameter toevoegen of verwijderen

  • ✔️ TOEGESTAAN: een ref parameter wijzigen in ref readonly

    Het wijzigen van een parameter van ref naar ref readonly is compatibel met de broncode voor bestaande aanroepplaatsen die argumenten doorgeven met de ref modifier. Deze aanroepen worden zonder enige wijziging gecompileerd. In tegenstelling tot het wijzigen van ref naar in, staat een ref readonly-parameter niet stilzwijgend toe dat aanroepen rvalues (niet-variabelen) doorgeven; de compiler geeft een waarschuwing als het argument geen variabele is. Bestaande ref oproepsites blijven geldig.

  • NIET TOEGESTAAN: een parameter wijzigen in in ref readonly

    Sites aanroepen die in-argumenten zonder de in-wijzigingsfunctie doorgeven (wat de compiler toestaat voor in-parameters), zullen een waarschuwing ontvangen wanneer de parameter naar ref readonly verandert, omdat ref readonly vereist dat het argument door verwijzing wordt doorgegeven. Mensen die waarschuwingen als fouten behandelen, zullen te maken krijgen met een wijziging die de bron breekt.

  • NIET TOEGESTAAN: de naam van een parameter wijzigen (inclusief het wijzigen van de hoofdletters)

    Dit wordt om twee redenen beschouwd als een breuk.

  • NIET TOEGESTAAN: Wijzigen van een ref retourwaarde in een ref readonly retourwaarde

  • ❌± NIET TOEGESTAAN: wijzigen van een ref readonly in een ref retourwaarde op een virtuele methode of interface

  • NIET TOEGESTAAN: Abstract toevoegen of verwijderen van een lid

  • NIET TOEGESTAAN: het virtuele trefwoord van een lid verwijderen

  • NIET TOEGESTAAN: het toevoegen van het virtuele trefwoord aan een lid

    Hoewel dit vaak geen belangrijke wijziging is, omdat de C#-compiler meestal callvirt Intermediate Language -instructies (IL) verzendt om niet-virtuele methoden aan te roepen (callvirt voert een null-controle uit, terwijl een normale aanroep niet werkt), is dit gedrag om verschillende redenen niet onveranderbaar:

    • C# is niet de enige taal die .NET ondersteunt.
    • De C#-compiler probeert steeds vaker om callvirt te optimaliseren tot een normale aanroep, wanneer de doelmethode niet-virtueel is en waarschijnlijk niet null is (zoals een methode die wordt geopend via de ?. null propagatie operator).

    Als u een methode virtueel maakt, betekent dit dat de gebruiker van de code deze vaak niet-virtueel zal aanroepen.

  • NIET TOEGESTAAN: Een virtueel clublid tot een abstracte functie maken

    Een virtueel lid biedt een methode-implementatie die kan worden overschreven door een afgeleide klasse. Een abstract lid biedt geen implementatie en moet worden overschreven.

  • NIET TOEGESTAAN: het verzegelde trefwoord toevoegen aan een interfacelid

    Als u toevoegt sealed aan een standaardinterfacelid, wordt dit niet-virtueel, waardoor de implementatie van een afgeleid type van dat lid niet kan worden aangeroepen.

  • NIET TOEGESTAAN: Een abstract lid toevoegen aan een openbaar type dat toegankelijke (openbare of beveiligde) constructors heeft en die niet is verzegeld

  • NIET TOEGESTAAN: het statische trefwoord van een lid toevoegen of verwijderen

  • NIET TOEGESTAAN: Een overload toevoegen die een bestaande overload overschrijft en een ander gedrag definieert

    Dit breekt bestaande clients die gebonden waren aan de vorige overbelasting. Als een klasse bijvoorbeeld één versie van een methode heeft die een UInt32 accepteert, zal een bestaande gebruiker succesvol aan die overload binden wanneer een Int32 waarde wordt doorgegeven. Als u echter een overbelasting toevoegt die een Int32 accepteert, wordt de compiler bij het opnieuw compileren of bij het gebruiken van late binding nu aan de nieuwe overbelasting gebonden. Als er verschillende gedragsresultaten optreden, kan dit een belangrijke wijziging zijn.

  • VEREIST BEOORDELING: Toevoegen OverloadResolutionPriorityAttribute aan een bestaande overbelasting of het wijzigen van de prioriteitswaarde

    Het OverloadResolutionPriorityAttribute beïnvloedt de overbeladingsresolutie op bronniveau: aanroepen die opnieuw worden gecompileerd, kunnen resulteren in een andere overbelading dan eerder. Het beoogde gebruik is om het kenmerk toe te voegen aan een nieuwe, betere overbelasting, zodat de compiler de voorkeur geeft aan bestaande kenmerken. Het toevoegen aan een bestaande overload of het wijzigen van de prioriteitswaarde van een reeds toegewezen overload kan een bronbrekende verandering zijn, omdat aanroepers die opnieuw compileren het gedrag kunnen wijzigen.

  • ✔️ TOEGESTAAN: De allows ref struct antibeperking toevoegen aan een algemene typeparameter

    Door allows ref struct toe te voegen, wordt uitgebreid welke typen als typeargumenten kunnen worden gebruikt door ref struct typen toe te staan. Bestaande bellers die niet-ref struct type argumenten gebruiken, worden niet beïnvloed. De algemene methode of het type moet voldoen aan de reference-veiligheidsregels voor alle instanties van die typeparameter.

  • NIET TOEGESTAAN: de allows ref struct anti-constraint verwijderen uit een generieke typeparameter

    Door allows ref struct te verwijderen, beperkt u welke typen bellers kunnen gebruiken als typeargumenten. Een aanroeper die een ref struct typeargument doorgeeft, wordt niet meer gecompileerd.

  • NIET TOEGESTAAN: Een constructor toevoegen aan een klasse die eerder geen constructor had zonder de parameterloze constructor toe te voegen

  • ❌± NIET TOEGESTAAN: readonly aan een veld toevoegen

  • NIET TOEGESTAAN: Vermindering van de zichtbaarheid van een lid

    Dit omvat het verminderen van de zichtbaarheid van een beschermd lid wanneer er toegankelijke (public of protected) constructors zijn en het type nietverzegeld is. Als dit niet het geval is, is het beperken van de zichtbaarheid van een beveiligd lid toegestaan.

    Het vergroten van de zichtbaarheid van een lid is toegestaan.

  • NIET TOEGESTAAN: het type van een element wijzigen

    De retourwaarde van een methode of het type eigenschap of veld kan niet worden gewijzigd. De signatuur van een methode die een Object retourneert, kan bijvoorbeeld niet worden gewijzigd naar een methode die een String retourneert, of omgekeerd.

  • NIET TOEGESTAAN: Een exemplaarveld toevoegen aan een struct die geen niet-openbare velden bevat

    Als een struct alleen openbare velden heeft of helemaal geen velden heeft, kunnen bellers lokale variabelen van dat structtype declareren zonder dat ze de constructor van de struct hoeven aan te roepen of eerst de lokale variabelen hoeven te initialiseren. Dit is mogelijk, zolang alle openbare velden op de struct zijn ingesteld voordat ze voor het eerst worden gebruikt. Het toevoegen van nieuwe velden - publiek of niet-publiek - aan een dergelijke struct is een bronbrekende wijziging voor deze aanroepers, omdat de compiler nu vereist dat de extra velden worden geïnitialiseerd.

    Daarnaast is het toevoegen van nieuwe velden (openbaar of niet-openbaar) aan een struct zonder velden of een struct met alleen openbare velden een breuk in binaire compatibiliteit voor bellers die [SkipLocalsInit] op hun code hebben toegepast. Omdat de compiler zich niet bewust was van deze velden tijdens het compileren, kan het IL verzenden dat de struct niet volledig initialiseert, waardoor de struct wordt gemaakt op basis van niet-geïnitialiseerde stackgegevens.

    Als een struct niet-openbare velden bevat, dwingt de compiler al initialisatie af via de constructor of default(T), en het toevoegen van nieuwe exemplaarvelden is geen belangrijke wijziging.

  • NIET TOEGESTAAN: Een bestaande gebeurtenis ontslaan toen deze nog nooit werd geactiveerd

Gedragswijzigingen

Assemblages

  • ✔️ TOEGESTAAN: Een assemblage draagbaar maken op voorwaarde dat dezelfde platforms nog steeds worden ondersteund

  • NIET TOEGESTAAN: het wijzigen van een assembly-naam

  • NIET TOEGESTAAN: Het wijzigen van de publieke sleutel van een assembly

Eigenschappen, velden, parameters en retourwaarden

  • ✔️ TOEGESTAAN: De waarde van een eigenschap, veld, retourwaarde of outparameter wijzigen in een meer afgeleid type

    Een methode die bijvoorbeeld een type Object retourneert, kan een String exemplaar retourneren. (De handtekening van de methode kan echter niet worden gewijzigd.)

  • ✔️ TOEGESTAAN: Het bereik van geaccepteerde waarden voor een eigenschap of parameter verhogen als het lid niet virtueel is

    Hoewel het bereik van waarden dat kan worden doorgegeven aan de methode of geretourneerd door het lid kan worden uitgebreid, kan het parameter- of lidtype niet worden gewijzigd. Terwijl de waarden die aan een methode worden doorgegeven, bijvoorbeeld kunnen worden uitgebreid van 0-124 tot 0-255, kan het parametertype niet veranderen van Byte in Int32.

  • NIET TOEGESTAAN: Het bereik van geaccepteerde waarden voor een eigenschap of parameter verhogen als het lid virtueel is

    Deze wijziging onderbreekt bestaande overschreven leden, die niet correct werken voor het uitgebreide bereik van waarden.

  • NIET TOEGESTAAN: het verlagen van het bereik van geaccepteerde waarden voor een eigenschap of parameter

  • NIET TOEGESTAAN: Het bereik van geretourneerde waarden voor een eigenschap, veld, retourwaarde of outparameter verhogen

  • NIET TOEGESTAAN: De geretourneerde waarden voor een eigenschap, veld, retourwaarde van een methode of uitvoerparameter wijzigen

  • NIET TOEGESTAAN: de standaardwaarde van een eigenschap, veld of parameter wijzigen

    Het wijzigen of verwijderen van een standaardwaarde voor een parameter is geen binair einde. Het verwijderen van een standaardwaarde voor een parameter is een brononderbreking en het wijzigen van een standaardwaarde van een parameter kan leiden tot een gedragsonderbreking na hercompilatie.

    Om deze reden is het verwijderen van standaardwaarden voor parameters acceptabel in het specifieke geval van het 'verplaatsen' van deze standaardwaarden naar een nieuwe methode-overbelasting om dubbelzinnigheid te voorkomen. Denk bijvoorbeeld aan een bestaande methode MyMethod(int a = 1). Als u een overbelasting van MyMethod introduceert met twee optionele parameters a en b, kunt u de compatibiliteit behouden door de standaardwaarde van a naar de nieuwe overbelasting te verplaatsen. Nu zijn MyMethod(int a) en MyMethod(int a = 1, int b = 2) de twee overbelastingen. Met dit patroon kunt u MyMethod() compileren.

  • NIET TOEGESTAAN: de precisie van een numerieke retourwaarde wijzigen

  • VEREIST OORDEEL: Een wijziging in de parsering van invoer en het genereren van nieuwe uitzonderingen (zelfs als het parseringsgedrag niet is opgegeven in de documentatie

  • NIET TOEGESTAAN: Casetypen toevoegen aan of verwijderen uit een union declaratie

    Het toevoegen of verwijderen van een casetype uit een union type is zowel een binair einde als een brononderbreking.

    Patroonkoppelingstests zijn niet langer volledig na het toevoegen van een casetype. De compiler markeert patroonvergelijkingsexpressies als niet-uitputtend. Bij runtime veroorzaken onverwachte waarden runtime-uitzonderingen. Als u een casetype verwijdert, wordt de constructordeclaratie voor dat casetype verwijderd.

Uitzonderingen

  • ✔️ TOEGESTAAN: Een meer afgeleide uitzondering genereren dan een bestaande uitzondering

    Omdat de nieuwe uitzondering een subklasse van een bestaande uitzondering is, blijft de eerdere uitzonderingsverwerkingscode de uitzondering verwerken. Bijvoorbeeld, in .NET Framework 4 begonnen de methoden voor cultuurcreatie en -ophaling een CultureNotFoundException te geven in plaats van een ArgumentException als de cultuur niet kon worden gevonden. Omdat CultureNotFoundException dit is afgeleid van ArgumentException, is dit een acceptabele wijziging.

  • ✔️ TOEGESTAAN: Een specifiekere uitzondering genereren dan NotSupportedException, NotImplementedException, NullReferenceException

  • ✔️ TOEGESTAAN: Een uitzondering genereren die als onherstelbaar wordt beschouwd

    Onherstelbare uitzonderingen moeten niet worden onderschept, maar in plaats daarvan worden afgehandeld door een catch-all-handler op hoog niveau. Daarom wordt verwacht dat gebruikers geen code hebben die deze expliciete uitzonderingen ondervangt. De onherstelbare uitzonderingen zijn:

  • ✔️ TOEGESTAAN: Een nieuwe uitzondering genereren in een nieuw codepad

    De uitzondering moet alleen van toepassing zijn op een nieuw codepad dat wordt uitgevoerd met nieuwe parameterwaarden of -status en die niet kan worden uitgevoerd door bestaande code die is gericht op de vorige versie.

  • ✔️ TOEGESTAAN: Een uitzondering verwijderen om robuuster gedrag of nieuwe scenario's mogelijk te maken

    Een Divide methode die eerder alleen positieve waarden afhandelde en anders een uitzondering ArgumentOutOfRangeException genereerde, kan worden veranderd om zowel negatieve als positieve waarden te ondersteunen zonder een uitzondering te genereren.

  • ✔️ TOEGESTAAN: De tekst van een foutbericht wijzigen

    Ontwikkelaars mogen niet afhankelijk zijn van de tekst van foutberichten, die ook veranderen op basis van de cultuur van de gebruiker.

  • NIET TOEGESTAAN: Een uitzondering werpen in elk ander geval dat hierboven niet wordt vermeld

  • NIET TOEGESTAAN: Een uitzondering verwijderen in een ander geval dat hierboven niet wordt vermeld

Kenmerken

  • ✔️ TOEGESTAAN: De waarde wijzigen van een kenmerk dat niet waarneembaar is

  • NIET TOEGESTAAN: de waarde wijzigen van een kenmerk dat waarneembaar is

  • VEREIST BEOORDELING: Een kenmerk verwijderen

    In de meeste gevallen is het verwijderen van een kenmerk (zoals NonSerializedAttribute) een belangrijke wijziging.

Platformondersteuning

  • ✔️ TOEGESTAAN: Ondersteuning van een bewerking op een platform dat eerder niet werd ondersteund

  • NIET TOEGESTAAN: er is geen ondersteuning of vereist nu een specifiek servicepack voor een bewerking die eerder op een platform werd ondersteund

Interne implementatiewijzigingen

  • VEREIST BEOORDELING: het oppervlak van een intern type wijzigen

    Dergelijke wijzigingen zijn over het algemeen toegestaan, hoewel ze privé-reflectie breken. In sommige gevallen, waarbij populaire bibliotheken van derden of een groot aantal ontwikkelaars afhankelijk zijn van de interne API's, zijn dergelijke wijzigingen mogelijk niet toegestaan.

  • VEREIST OORDEEL: de interne implementatie van een lid wijzigen

    Deze wijzigingen zijn over het algemeen toegestaan, hoewel ze privé-reflectie verbreken. In sommige gevallen is klantcode vaak afhankelijk van persoonlijke reflectie of wanneer de wijziging onbedoelde bijwerkingen introduceert, zijn deze wijzigingen mogelijk niet toegestaan.

  • ✔️ TOEGESTAAN: De prestaties van een bewerking verbeteren

    De mogelijkheid om de prestaties van een bewerking te wijzigen is essentieel, maar dergelijke wijzigingen kunnen code breken die afhankelijk is van de huidige snelheid van een bewerking. Dit geldt met name voor code die afhankelijk is van de timing van asynchrone bewerkingen. De prestatiewijziging mag geen effect hebben op ander gedrag van de BETREFFENDE API; anders wordt de wijziging onderbroken.

  • ✔️ TOEGESTAAN: Het indirect (en vaak nadelig) veranderen van de prestaties van een handeling

    Als de betreffende wijziging om een andere reden niet wordt gecategoriseerd als breuk, is dit acceptabel. Vaak moeten er acties worden uitgevoerd die extra bewerkingen kunnen bevatten of die nieuwe functionaliteit toevoegen. Dit is vrijwel altijd van invloed op de prestaties, maar kan essentieel zijn om de betreffende API naar verwachting te laten functioneren.

  • NIET TOEGESTAAN: een synchrone API wijzigen in asynchroon (en omgekeerd)

Codewijzigingen

  • ✔️ TOEGESTAAN: params toevoegen aan een parameter

  • NIET TOEGESTAAN: een struct wijzigen in een klasse en omgekeerd

  • NIET TOEGESTAAN: het gecontroleerde statement toevoegen aan een codeblok

    Deze wijziging kan ertoe leiden dat code die eerder is uitgevoerd, een OverflowException genereert, wat onaanvaardbaar is.

  • VERBODEN: params verwijderen van een parameter

  • NIET TOEGESTAAN: Het verzamelingstype van een params parameter wijzigen

    Vanaf C# 13 params ondersteunen parameters niet-arrayverzamelingstypen, waaronder Span<T>, ReadOnlySpan<T> structs of klassetypen die IEnumerable<T> implementeren met een toegankelijke parameterloze constructor en een instantieAdd methode, en specifieke interfaces zoals IList<T>. Als u het verzamelingstype van een bestaande params-parameter wijzigt (bijvoorbeeld van params T[] naar params ReadOnlySpan<T>) verandert u de IL-ondertekening van de methode, wat een binaire breuk is. Oproepen die tegen de vorige versie zijn gecompileerd, moeten opnieuw worden gecompileerd.

  • ✔️ TOEGESTAAN: Een extensiemethode converteren naar de syntaxis van het extensiebloklid

    Vanaf C# 14 kunt u extensieleden declareren met behulp van extension blokken naast de oudere thisparametersyntaxis. Beide formulieren genereren identieke IL, zodat bellers er geen onderscheid tussen kunnen maken. Het converteren van bestaande extensiemethoden naar de syntaxis van het nieuwe extensieblok is binair en bron compatibel.

  • NIET TOEGESTAAN: de volgorde wijzigen waarin gebeurtenissen worden geactiveerd

    Ontwikkelaars kunnen redelijkerwijs verwachten dat gebeurtenissen in dezelfde volgorde worden geactiveerd en dat ontwikkelaarscode vaak afhankelijk is van de volgorde waarin gebeurtenissen worden geactiveerd.

  • NIET TOEGESTAAN: het oproepen van een gebeurtenis bij een bepaalde actie verwijderen

  • NIET TOEGESTAAN: Het aantal keren wijzigen dat bepaalde gebeurtenissen worden aangeroepen

  • NIET TOEGESTAAN: Het toevoegen van FlagsAttribute aan een opsommingstype

Zie ook