Aracılığıyla paylaş


AOT uyarılarına giriş

Uygulamanızı Yerel AOT olarak yayımlarken, derleme işlemi çalışma zamanında uygulamayı desteklemek için gereken tüm yerel kodu ve veri yapılarını oluşturur. Bu, uygulamayı soyut terimlerle (sanal makine için bir program) açıklayan biçimlerden yürüten ve çalışma zamanında isteğe bağlı yerel gösterimler oluşturan yerel olmayan dağıtımlardan farklıdır.

Program bölümlerinin soyut gösterimlerinde yerel gösterime bire bir eşleme yoktur. Örneğin, genel List<T>.Add yöntemin soyut açıklaması, verilen T için özelleştirilmesi gereken sonsuz olabilecek yerel yöntem gövdelerine eşler (örneğin, List<int>.Add ve List<double>.Add).

Soyut kodun yerel kodla ilişkisi bire bir olmadığından, derleme işleminin derleme zamanında yerel kod gövdelerinin ve veri yapılarının tam bir listesini oluşturması gerekir. Bazı .NET API'leri için derleme zamanında bu listeyi oluşturmak zor olabilir. API derleme zamanında beklenmeyecek bir şekilde kullanılırsa, çalışma zamanında bir özel durum oluşturulur.

Yerel AOT olarak dağıtılırken davranış değişikliklerini önlemek için .NET SDK, "AOT uyarıları" aracılığıyla AOT uyumluluğunun statik analizini sağlar. Derleme, AOT ile uyumlu olmayabilecek kodu bulduğunda AOT uyarıları oluşturulur. AOT ile uyumlu olmayan kod, Yerel AOT olarak derlendikten sonra bir uygulamada davranış değişikliklerine veya hatta hatalara neden olabilir. İdeal olan, Yerel AOT kullanan tüm uygulamalarda AOT uyarısı olmamasıdır. AOT uyarıları varsa, Doğal AOT olarak derledikten sonra uygulamanızı kapsamlı bir şekilde test ederek davranış değişikliklerinin olmadığını doğrulayın.

AOT uyarıları örnekleri

Çoğu C# kodu için, hangi yerel kodun oluşturulması gerektiğini belirlemek kolaydır. Yerel derleyici, yöntem gövdelerini araştırabilir ve hangi yerel kod ve veri yapılarının erişildiğini bulabilir. Ne yazık ki yansıma gibi bazı özellikler önemli bir sorun oluşturur. Aşağıdaki kodu inceleyin:

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

struct GenericType<T> { }

Yukarıdaki program çok kullanışlı olmasa da, uygulamayı Yerel AOT olarak oluştururken sonsuz sayıda genel türün oluşturulmasını gerektiren aşırı bir durumu temsil eder. Yerel AOT olmadan, program belleği tükenene kadar çalışır. Yerel AOT ile, gerekli türlerin hepsini (sınırsız sayıda tür) oluştursaydık bile bunu derlemek yine de mümkün olmazdı.

Bu durumda, Native AOT derlemesi MakeGenericType satırında aşağıdaki uyarıyı verir:

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.

Çalışma zamanında, uygulama MakeGenericType çağrısından bir istisna fırlatır.

AOT uyarılarına tepki gösterme

AOT uyarıları, Yerel AOT derlemelerine öngörülebilirlik getirme amacını taşımaya yöneliktir. AOT uyarılarının çoğu, senaryoyu desteklemek için yerel kodun oluşturulmamış olduğu durumlarda olası çalışma zamanı özel durumuyla ilgilidir. En geniş kategori: RequiresDynamicCodeAttribute.

DynamicCode gerektirir

RequiresDynamicCodeAttribute basit ve geniştir: Bu, üyeye AOT ile uyumsuz olarak açıklama eklendiği anlamına gelen bir özniteliktir. Bu ek açıklama, üyenin çalışma zamanında yeni yerel kod oluşturmak için yansıma veya başka bir mekanizma kullanabileceği anlamına gelir. Bu öznitelik, kod temel olarak AOT uyumlu olmadığında veya yerel bağımlılık derleme zamanında statik olarak tahmin etmek için çok karmaşık olduğunda kullanılır. Bu genellikle API, yansıma yayma veya diğer çalışma zamanı kod oluşturma teknolojilerini kullanan Type.MakeGenericType yöntemler için geçerlidir. Aşağıdaki kodda bir örnek gösterilmektedir.

[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();
}

RequiresDynamicCode için çok fazla geçici çözüm yoktur. En iyi düzeltme, Native AOT uyumlu olarak oluştururken yöntemi çağırmaktan kaçınmak ve AOT uyumlu başka bir yöntem kullanmaktır. Bir kitaplık yazıyorsanız ve yöntemi çağırıp çağırmamak sizin denetiminizde değilse, kendi yönteminize de RequiresDynamicCode ekleyebilirsiniz. Bu, yönteminize AOT uyumlu olmadığı için ek açıklama ekler. RequiresDynamicCode eklemek, açıklamalı yöntemdeki tüm AOT uyarılarını sessize alır ancak başka biri çağırdığında bir uyarı üretir. Bu nedenle, kitaplık yazarlarının uyarıyı açık API'ye üst seviyeye çıkarması genellikle daha yararlıdır.

Bir şekilde çağrının güvenli olduğunu saptayabiliyorsanız ve tüm yerel kod çalışma zamanında kullanılabilir olacaksa, kullanarak UnconditionalSuppressMessageAttributeuyarıyı da gizleyebilirsiniz. Örneğin:

[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, SuppressMessage gibidir ancak publish ve diğer derleme sonrası araçlar tarafından görülebilir. SuppressMessage ve #pragma yönergeleri yalnızca kaynakta bulunur, bu nedenle derlemedeki uyarıları susturmak için kullanılamazlar.

Dikkat

AOT uyarılarını bastırırken dikkatli olun. Arama artık AOT uyumlu olabilir, ancak kodunuzu güncelleştirdikçe bu değişebilir ve tüm gizlemeleri gözden geçirmeyi unutabilirsiniz.