Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
När du publicerar din applikation som Native AOT skapar byggprocessen all den inhemska kod och datastrukturer som krävs för att stödja applikationen vid körningstid. Detta skiljer sig från icke-interna distributioner, som kör programmet från format som beskriver programmet i abstrakta termer (ett program för en virtuell dator) och skapar interna representationer på begäran vid körning.
De abstrakta representationerna av programdelar har ingen en-till-en-mappning till den interna representationen. Till exempel mappar den abstrakta beskrivningen av den generiska List<T>.Add metoden till potentiellt oändliga inbyggda metodkroppar som måste vara specialiserade för den angivna T (till exempel List<int>.Add och List<double>.Add).
Eftersom relationen mellan abstrakt kod och intern kod inte är en-till-en måste byggprocessen skapa en fullständig lista över inbyggda kodkroppar och datastrukturer vid bygget. Det kan vara svårt att skapa den här listan vid byggtiden för några av .NET-API:erna. Om API:et används på ett sätt som inte förväntades vid bygget genereras ett undantag vid körning.
För att förhindra ändringar i beteende vid distribution som intern AOT tillhandahåller .NET SDK statisk analys av AOT-kompatibilitet via "AOT-varningar". AOT-varningar skapas när bygget hittar kod som kanske inte är kompatibel med AOT. Kod som inte är AOT-kompatibel kan ge beteendeförändringar eller till och med kraschar i ett program efter att den har skapats som intern AOT. Helst bör alla program som använder intern AOT inte ha några AOT-varningar. Om det finns AOT-varningar, se till att det inte finns några beteendeförändringar genom att noggrant testa din app efter att den har byggts som Native AOT.
Exempel på AOT-varningar
För de flesta C#-kod är det enkelt att avgöra vilken intern kod som behöver genereras. Den inbyggda kompilatorn kan gå igenom metodkropparna och hitta vilka interna kod- och datastrukturer som används. Tyvärr utgör vissa funktioner, till exempel reflektion, ett betydande problem. Överväg följande kod:
Type t = typeof(int);
while (true)
{
t = typeof(GenericType<>).MakeGenericType(t);
Console.WriteLine(Activator.CreateInstance(t));
}
struct GenericType<T> { }
Även om ovanstående program inte är särskilt användbart representerar det ett extremt fall som kräver att ett oändligt antal generiska typer skapas när programmet skapas som intern AOT. Utan intern AOT skulle programmet köras tills minnet tar slut. Med intern AOT skulle vi inte ens kunna skapa den om vi skulle generera alla nödvändiga typer (det oändliga antalet av dem).
I det här fallet utfärdar native AOT-byggprocessen följande varning på MakeGenericType raden.
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.
När programmet körs kommer det verkligen att utlösa ett undantag från anropet MakeGenericType.
Reagera på AOT-varningar
AOT-varningarna är avsedda att ge förutsägbarhet till nativa AOT-kompileringar. En majoritet av AOT-varningar handlar om möjliga körningsfel i situationer då inbyggd kod inte genererades för att stödja scenariot. Den bredaste kategorin är RequiresDynamicCodeAttribute.
Kräver Dynamisk Kod
RequiresDynamicCodeAttribute är enkelt och brett: det är ett attribut som innebär att medlemmen har kommenterats som inkompatibel med AOT. Den här kommentaren innebär att medlemmen kan använda reflektion eller någon annan mekanism för att skapa ny ursprunglig kod under körning. Det här attributet används när koden i grunden inte är AOT-kompatibel, eller om det interna beroendet är för komplext för att statiskt förutsäga vid byggtid. Detta gäller ofta för metoder som använder Type.MakeGenericType API:et, tekniker såsom reflektion och utsändning eller andra tekniker för generering av kod under körning. Följande kod visar ett exempel.
[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();
}
Det finns inte många lösningar för RequiresDynamicCode. Den bästa korrigeringen är att undvika att anropa metoden över huvud taget när du skapar som Native AOT och använda något annat som är AOT-kompatibelt. Om du skriver ett bibliotek och det inte är inom din kontroll att anropa metoden, kan du också lägga till RequiresDynamicCode i din egen metod. Detta kommenterar din metod som inte AOT-kompatibel. Om du lägger till RequiresDynamicCode tystar du alla AOT-varningar i den kommenterade metoden, men skapar en varning när någon annan anropar den. Därför är det mest användbart för biblioteksförfattare att "bubbla upp" varningen till ett offentligt API.
Om du kan fastställa att anropet är säkert och att all inbyggd kod kommer att vara tillgänglig vid körning, kan du också undertrycka varningen med UnconditionalSuppressMessageAttribute. Till exempel:
[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 är som SuppressMessage men det kan ses av publish och andra verktyg efter bygget.
SuppressMessage och #pragma direktiv finns bara i källkoden, så de kan inte användas för att tysta varningar från kompileringen.
Försiktighet
Var försiktig när du ignorerar AOT-varningar. Anropet kan vara AOT-kompatibelt nu, men när du uppdaterar koden kan det ändras och du kanske glömmer att granska alla undertryckningar.