Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Beim Veröffentlichen Ihrer Anwendung als Native AOT erzeugt der Buildprozess allen erforderlichen systemeigenen Code und alle Datenstrukturen, die zur Unterstützung der Anwendung während der Laufzeit benötigt werden. Dies unterscheidet sich von nicht nativen Bereitstellungen, die die Anwendung aus Formaten ausführen, die die Anwendung in abstrakten Begriffen beschreiben (ein Programm für einen virtuellen Computer) und systemeigene Darstellungen bei Bedarf zur Laufzeit erstellen.
Die abstrakten Darstellungen von Programmteilen weisen keine 1:1-Zuordnung zur nativen Darstellung auf. Die abstrakte Beschreibung der generischen List<T>.Add
-Methode wird z. B. potenziell unendlichen nativen Methodenkörpern zugeordnet, die für den angegebenen T
(z. B. List<int>.Add
und List<double>.Add
) spezialisiert werden müssen.
Da die Beziehung von abstraktem Code zu systemeigenem Code nicht 1:1 ist, muss der Buildprozess zur Erstellungszeit eine vollständige Liste der systemeigenen Codetextkörper und Datenstrukturen erstellen. Es kann schwierig sein, diese Liste zur Erstellungszeit für einige der .NET-APIs zu erstellen. Wenn die API in einer Weise verwendet wird, die zur Buildzeit nicht erwartet wurde, wird zur Laufzeit eine Ausnahme ausgelöst.
Um Änderungen des Verhaltens bei der Bereitstellung als native AOT zu verhindern, stellt das .NET SDK statische Analysen der AOT-Kompatibilität über "AOT-Warnungen" bereit. AOT-Warnungen werden erstellt, wenn der Build Code findet, der möglicherweise nicht mit AOT kompatibel ist. Code, der nicht AOT-kompatibel ist, kann Verhaltensänderungen oder sogar Abstürze in einer Anwendung verursachen, nachdem es als native AOT erstellt wurde. Im Idealfall sollten alle Anwendungen, die native AOT verwenden, keine AOT-Warnungen enthalten. Wenn AOT-Warnungen vorhanden sind, stellen Sie sicher, dass es keine Verhaltensänderungen gibt, indem Sie Ihre App nach dem Erstellen als native AOT gründlich testen.
Beispiele für AOT-Warnungen
Für den meisten C#-Code ist es einfach zu bestimmen, welcher systemeigene Code generiert werden muss. Der systemeigene Compiler kann die Methodentexte durchlaufen und ermitteln, auf welche systemeigenen Code- und Datenstrukturen zugegriffen wird. Leider stellen einige Merkmale, z. B. Spiegelungen, ein erhebliches Problem dar. Beachten Sie den folgenden Code:
Type t = typeof(int);
while (true)
{
t = typeof(GenericType<>).MakeGenericType(t);
Console.WriteLine(Activator.CreateInstance(t));
}
struct GenericType<T> { }
Obwohl das obige Programm nicht sehr nützlich ist, stellt es einen Extremfall dar, der eine unendliche Anzahl generischer Typen erfordert, die beim Erstellen der Anwendung als native AOT erstellt werden müssen. Ohne native AOT würde das Programm ausgeführt, bis ihm der Arbeitsspeicher ausgeht. Mit Native AOT könnten wir es nicht selbst erstellen, wenn wir alle erforderlichen Typen (die unendliche Anzahl davon) generieren würden.
In diesem Fall gibt der Native AOT-Build die folgende Warnung in der MakeGenericType
-Zeile aus:
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.
Zur Laufzeit löst die Anwendung tatsächlich eine Ausnahme vom MakeGenericType
-Aufruf aus.
Reagieren auf AOT-Warnungen
Die AOT-Warnungen sollen die Vorhersagbarkeit für Native AOT-Builds verbessern. Die meisten AOT-Warnungen beziehen sich auf mögliche Laufzeitausnahmen in Situationen, in denen zur Unterstützung des Szenarios kein nativer Code generiert wurde. Die umfassendste Kategorie ist RequiresDynamicCodeAttribute
.
ErfordertDynamischenCode
RequiresDynamicCodeAttribute ist einfach und breit: Es handelt sich um ein Attribut, das bedeutet, dass das Element als inkompatibel mit AOT gekennzeichnet wurde. Diese Anmerkung bedeutet, dass der Member möglicherweise Reflexion oder einen anderen Mechanismus verwendet, um zur Laufzeit neuen nativen Code zu erstellen. Dieses Attribut wird verwendet, wenn Code grundsätzlich nicht AOT-kompatibel ist oder die systemeigene Abhängigkeit zu komplex ist, um zur Buildzeit statisch vorherzusagen. Dies gilt häufig für Methoden, die die Type.MakeGenericType
-API, Reflection-Emit oder andere Laufzeit-Code-Generierungs-Technologien verwenden. Der folgende Code zeigt ein Beispiel.
[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();
}
Es gibt nicht viele Alternativen für RequiresDynamicCode
. Die beste Lösung besteht darin, beim Erstellen als Native AOT die Methode nicht aufzurufen und stattdessen etwas anderes zu verwenden, das AOT-kompatibel ist. Wenn Sie eine Bibliothek schreiben und es nicht in Ihrer Kontrolle liegt, ob die Methode aufgerufen werden soll, können Sie RequiresDynamicCode
auch Ihrer eigenen Methode hinzufügen. Dadurch wird Ihre Methode als nicht AOT-kompatibel angemerkt. Das Hinzufügen von RequiresDynamicCode
unterdrückt alle AOT-Warnungen in der annotierten Methode, erzeugt jedoch eine Warnung, wenn sie von jemand anderem aufgerufen wird. Aus diesem Grund ist es vor allem für Bibliotheksautoren nützlich, die Warnung an eine öffentliche API weiterzuleiten.
Wenn Sie feststellen können, ob der Aufruf sicher ist und der gesamte Native-Code zur Laufzeit verfügbar ist, können Sie die Warnung auch mit UnconditionalSuppressMessageAttribute unterdrücken. Beispiel:
[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
ist wie SuppressMessage
, kann aber von publish
und anderen Post-Build-Tools erkannt werden. SuppressMessage
- und #pragma
-Anweisungen sind nur in der Quelle vorhanden, sodass sie nicht verwendet werden können, um Warnungen vor dem Build zu ignorieren.
Vorsicht
Unterdrücken Sie AOT-Warnungen mit Vorsicht. Der Aufruf kann jetzt AOT-kompatibel sein, aber wenn Sie Ihren Code aktualisieren, kann sich dies ändern, und Sie vergessen möglicherweise, alle Unterdrückungen zu überprüfen.