Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Podczas publikowania aplikacji jako natywnej AOT proces kompilacji generuje cały kod natywny i struktury danych wymagane do obsługi aplikacji w czasie wykonywania. Różni się to od wdrożeń innych niż natywne, które wykonują aplikację z formatów opisujących aplikację w sposób abstrakcyjny (program dla maszyny wirtualnej) i tworzą natywne reprezentacje na żądanie w czasie wykonywania.
Abstrakcyjne reprezentacje części programu nie mają bezpośredniego odwzorowania na natywną reprezentację. Na przykład abstrakcyjny opis ogólnej metody List<T>.Add
odzwierciedla się w potencjalnie nieskończonych ciałach metod natywnych, które muszą być wyspecjalizowane dla danego T
(na przykład List<int>.Add
i List<double>.Add
).
Ponieważ relacja kodu abstrakcyjnego z kodem natywnym nie jest jednorazowa, proces kompilacji musi utworzyć pełną listę natywnych treści kodu i struktur danych w czasie kompilacji. Utworzenie tej listy w czasie kompilacji dla niektórych interfejsów API platformy .NET może być trudne. Jeśli interfejs API jest używany w sposób, który nie był oczekiwany w czasie kompilacji, wyjątek zostanie zgłoszony w czasie wykonywania.
Aby zapobiec zmianom zachowania podczas wdrażania jako natywna funkcja AOT, zestaw SDK platformy .NET zapewnia statyczną analizę zgodności funkcji AOT za pomocą "ostrzeżeń AOT". Ostrzeżenia dotyczące AOT są generowane, gdy kompilacja znajdzie kod, który może nie być zgodny z usługą AOT. Kod, który nie jest zgodny z funkcją AOT, może generować zmiany behawioralne, a nawet ulegać awarii w aplikacji po utworzeniu jej jako natywnej AOT. W idealnym przypadku wszystkie aplikacje korzystające z natywnej funkcji AOT nie powinny mieć ostrzeżeń dotyczących AOT. Jeśli istnieją jakiekolwiek ostrzeżenia AOT, upewnij się, że nie ma żadnych zmian zachowania przez dokładne przetestowanie aplikacji po jej utworzeniu w wersji natywnej AOT.
Przykłady ostrzeżeń AOT
W przypadku większości kodu w języku C# łatwo jest określić, jaki kod natywny musi zostać wygenerowany. Kompilator macierzysty może poznać elementy metody i znaleźć, do czego uzyskuje się dostęp kod natywny i struktury danych. Niestety, niektóre funkcje, takie jak odbicie, stanowią znaczący problem. Rozważ następujący kod:
Type t = typeof(int);
while (true)
{
t = typeof(GenericType<>).MakeGenericType(t);
Console.WriteLine(Activator.CreateInstance(t));
}
struct GenericType<T> { }
Chociaż powyższy program nie jest bardzo przydatny, reprezentuje skrajny przypadek, który wymaga nieskończonej liczby typów ogólnych do utworzenia podczas kompilowania aplikacji jako natywnej AOT. Bez natywnego AOT, program działałby, dopóki nie zabraknie pamięci. W przypadku natywnej funkcji AOT nie będziemy w stanie utworzyć jej nawet wtedy, gdy będziemy generować wszystkie niezbędne typy (nieskończona liczba z nich).
W takim przypadku kompilacja natywna AOT generuje następujące ostrzeżenie w wierszu MakeGenericType
.
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.
W czasie wykonywania aplikacja rzeczywiście zgłosi wyjątek od wywołania MakeGenericType
.
Reaguj na ostrzeżenia dotyczące AOT
Ostrzeżenia AOT mają na celu wprowadzenie przewidywalności do natywnych kompilacji AOT. Większość ostrzeżeń AOT dotyczy możliwego wyjątku podczas wykonywania w sytuacjach, gdy kod natywny nie został skompilowany w celu obsługi scenariusza. Najszersza kategoria to RequiresDynamicCodeAttribute
.
WymagaDynamicznegoKodu
RequiresDynamicCodeAttribute jest prosty i ogólny: jest to atrybut, oznaczający, że członek został oznaczony jako niezgodny z AOT. Ta adnotacja oznacza, że członek może używać reflection lub innego mechanizmu do tworzenia nowego kodu natywnego w czasie wykonywania. Ten atrybut jest używany, gdy kod nie jest zasadniczo zgodny z funkcją AOT lub zależność natywna jest zbyt złożona, aby statycznie przewidywać w czasie kompilacji. Często dotyczy to metod korzystających z interfejsu Type.MakeGenericType
API, emisji odbicia lub innych technologii generowania kodu w czasie wykonywania. Poniższy kod przedstawia przykład.
[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();
}
Nie ma wielu obejść dla programu RequiresDynamicCode
. Najlepszym rozwiązaniem jest unikanie wywoływania metody w ogóle podczas kompilowania jako natywnej funkcji AOT i używania innego elementu zgodnego z funkcją AOT. Jeśli piszesz bibliotekę i nie masz kontroli nad tym, czy wywołać metodę, możesz także dodać RequiresDynamicCode
do własnej metody. To oznaczy twoją metodę jako niezgodną z AOT. Dodanie RequiresDynamicCode
powoduje wyciszenie wszystkich ostrzeżeń AOT w metodzie z adnotacjami, ale spowoduje wygenerowanie ostrzeżenia za każdym razem, gdy ktoś inny go wywoła. Z tego powodu jest to przede wszystkim przydatne dla autorów bibliotek, aby przekazywać ostrzeżenie do publicznego API.
Jeśli w jakiś sposób można określić, że wywołanie jest bezpieczne, a cały kod natywny będzie dostępny w czasie wykonywania, możesz również pominąć ostrzeżenie przy użyciu polecenia UnconditionalSuppressMessageAttribute. Przykład:
[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
jest jak SuppressMessage
, ale można go zobaczyć za pomocą publish
innych narzędzi po kompilacji.
SuppressMessage
dyrektywy i #pragma
są obecne tylko w źródle, więc nie można ich używać do wyciszenia ostrzeżeń z kompilacji.
Ostrzeżenie
Zachowaj ostrożność podczas pomijania ostrzeżeń dotyczących AOT. Wywołanie może być teraz zgodne z AOT, ale gdy aktualizujesz swój kod, może się to zmienić i możesz zapomnieć o przejrzeniu wszystkich wyłączeń.