Delen via


Inleiding tot AOT-waarschuwingen

Wanneer u uw toepassing publiceert als systeemeigen AOT, produceert het buildproces alle systeemeigen code en gegevensstructuren die nodig zijn om de toepassing tijdens runtime te ondersteunen. Dit verschilt van niet-systeemeigen implementaties, die de toepassing uitvoeren op basis van indelingen die de toepassing in abstracte termen beschrijven (een programma voor een virtuele machine) en systeemeigen weergaven op aanvraag maken tijdens runtime.

De abstracte representaties van programmaonderdelen hebben geen een-op-een-toewijzing aan systeemeigen weergave. De abstracte beschrijving van de algemene List<T>.Add methode wordt bijvoorbeeld toegewezen aan mogelijk oneindige systeemeigen methode-lichamen die speciaal moeten zijn voor de gegeven T (bijvoorbeeld List<int>.Add en List<double>.Add).

Omdat de relatie van abstracte code naar systeemeigen code niet een-op-een is, moet het buildproces een volledige lijst maken met systeemeigen codeteksten en gegevensstructuren tijdens de build. Het kan lastig zijn om deze lijst tijdens de build te maken voor sommige .NET-API's. Als de API wordt gebruikt op een manier die niet werd verwacht tijdens de build, wordt er tijdens runtime een uitzondering gegenereerd.

Om te voorkomen dat wijzigingen in gedrag optreden bij het implementeren als systeemeigen AOT, biedt de .NET SDK statische analyse van AOT-compatibiliteit via 'AOT-waarschuwingen'. AOT-waarschuwingen worden geproduceerd wanneer de build code vindt die mogelijk niet compatibel is met AOT. Code die niet compatibel is met AOT, kan gedragswijzigingen veroorzaken of zelfs crashes in een toepassing veroorzaken nadat deze is gebouwd als systeemeigen AOT. In het ideale geval mogen alle toepassingen die gebruikmaken van Native AOT geen AOT-waarschuwingen hebben. Als er AOT-waarschuwingen zijn, moet u ervoor zorgen dat er geen gedragswijzigingen zijn door uw app grondig te testen na het bouwen als systeemeigen AOT.

Voorbeelden van AOT-waarschuwingen

Voor de meeste C#-code is het eenvoudig om te bepalen welke systeemeigen code moet worden gegenereerd. De systeemeigen compiler kan de methodeteksten doorlopen en vinden welke systeemeigen code en gegevensstructuren worden geopend. Helaas vormen sommige functies, zoals weerspiegeling, een belangrijk probleem. Kijk eens naar de volgende code:

Type t = typeof(int);
while (true)
{
    t = typeof(GenericType<>).MakeGenericType(t);
    Console.WriteLine(Activator.CreateInstance(t));
}

struct GenericType<T> { }

Hoewel het bovenstaande programma niet erg nuttig is, is het een extreem geval waarvoor een oneindig aantal algemene typen moet worden gemaakt bij het bouwen van de toepassing als Systeemeigen AOT. Zonder systeemeigen AOT zou het programma worden uitgevoerd totdat het onvoldoende geheugen meer heeft. Met systeemeigen AOT zouden we het zelfs niet kunnen bouwen als we alle benodigde typen zouden genereren (het oneindige aantal).

In dit geval geeft systeemeigen AOT-build de volgende waarschuwing op de MakeGenericType regel:

AOT analysis warning IL3050: Program.<Main>$(String[]): Using member 'System.Type.MakeGenericType(Type[])' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. The native code for this instantiation might not be available at runtime.

Tijdens de uitvoering genereert de toepassing inderdaad een uitzondering van de MakeGenericType aanroep.

Reageren op AOT-waarschuwingen

De AOT-waarschuwingen zijn bedoeld om voorspelbaarheid te bieden aan systeemeigen AOT-builds. Een meerderheid van de AOT-waarschuwingen gaat over mogelijke runtime-uitzonderingen in situaties waarin systeemeigen code niet is gegenereerd om het scenario te ondersteunen. De breedste categorie is RequiresDynamicCodeAttribute.

RequiresDynamicCode

RequiresDynamicCodeAttribute is eenvoudig en breed: het is een kenmerk dat betekent dat het lid is geannoteerd als niet compatibel met AOT. Deze aantekening betekent dat het lid reflectie of een ander mechanisme kan gebruiken om nieuwe systeemeigen code te maken tijdens runtime. Dit kenmerk wordt gebruikt wanneer code fundamenteel niet compatibel is met AOT of de systeemeigen afhankelijkheid te complex is om statisch te voorspellen tijdens de build. Dit geldt vaak voor methoden die gebruikmaken van de Type.MakeGenericType API, reflectie-emit of andere technologieën voor het genereren van runtimecode. De volgende code laat een voorbeeld zien.

[RequiresDynamicCode("Use 'MethodFriendlyToAot' instead")]
void MethodWithReflectionEmit() { ... }

void TestMethod()
{
    // IL3050: Using method 'MethodWithReflectionEmit' which has 'RequiresDynamicCodeAttribute'
    // can break functionality when AOT compiling. Use 'MethodFriendlyToAot' instead.
    MethodWithReflectionEmit();
}

Er zijn niet veel tijdelijke oplossingen voor RequiresDynamicCode. De beste oplossing is om te voorkomen dat de methode helemaal wordt aangeroepen bij het bouwen als systeemeigen AOT en iets anders gebruikt dat compatibel is met AOT. Als u een bibliotheek schrijft en deze niet in uw besturingselement staat of u de methode wilt aanroepen, kunt u ook toevoegen RequiresDynamicCode aan uw eigen methode. Hiermee wordt een aantekeningen toegevoegd aan uw methode als niet compatibel met AOT. Als RequiresDynamicCode u alle AOT-waarschuwingen toevoegt in de geannoteerde methode, wordt een waarschuwing weergegeven wanneer iemand anders deze aanroept. Daarom is het vooral handig om bibliotheekauteurs de waarschuwing voor een openbare API te laten 'opbellen'.

Als u op een of andere manier kunt bepalen dat de aanroep veilig is en alle systeemeigen code tijdens runtime beschikbaar is, kunt u de waarschuwing ook onderdrukken met behulp van UnconditionalSuppressMessageAttribute. Voorbeeld:

[RequiresDynamicCode("Use 'MethodFriendlyToAot' instead")]
void MethodWithReflectionEmit() { ... }

[UnconditionalSuppressMessage("Aot", "IL3050:RequiresDynamicCode",
    Justification = "The unfriendly method is not reachable with AOT")]
void TestMethod()
{
    If (RuntimeFeature.IsDynamicCodeSupported)
        MethodWithReflectionEmit(); // warning suppressed
}

UnconditionalSuppressMessage is net, SuppressMessage maar het kan worden gezien door publish en andere hulpprogramma's na de build. SuppressMessage en #pragma instructies zijn alleen aanwezig in de bron, zodat ze niet kunnen worden gebruikt om waarschuwingen van de build stil te leggen.

Let op

Wees voorzichtig bij het onderdrukken van AOT-waarschuwingen. De aanroep is nu mogelijk compatibel met AOT, maar als u uw code bijwerkt, kan dit veranderen en vergeet u mogelijk alle onderdrukkingen te controleren.