Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Uygulamanızda kırpmayı etkinleştirdiğinizde. .NET SDK, kırpmayla uyumlu olmayabilecek kod desenlerini algılamak için statik analiz gerçekleştirir. Kırpma uyarıları, kırpma sonrasında davranış değişikliklerine veya kilitlenmelere neden olabilecek olası sorunları gösterir.
Kırpma kullanan bir uygulama herhangi bir kırpma uyarısı üretmemelidir. Herhangi bir kırpma uyarısı varsa, herhangi bir davranış değişikliği olmadığından emin olmak için kırpma işleminden sonra uygulamayı kapsamlı bir şekilde test edin.
Bu makale, kırpma uyarılarını ele almak için pratik iş akışları sağlar. Bu uyarıların neden oluştuğu ve kırpmanın nasıl çalıştığı hakkında daha ayrıntılı bilgi için bkz. Kırpma analizini anlama.
Uyarı kategorilerini anlama
Kırpma uyarıları iki ana kategoriye ayrılır:
Kod kırpma ile uyumlu değil - ile RequiresUnreferencedCodeAttributeişaretlendi. Kod temel olarak çözümlenebilir hale getirilemez (örneğin, dinamik derleme yükleme veya karmaşık yansıma desenleri). yöntemi uyumsuz olarak işaretlenir ve çağıranlar uyarı alır.
Gereksinimleri olan kod - DynamicallyAccessedMembersAttribute ile açıklamalı. Yansıma kullanılır, ancak türler derleme zamanında bilinir. Gereksinimler karşılandığında kod tamamen kırpma uyumlu hale gelir.
İş Akışı: Doğru yaklaşımı belirleme
Kırpma uyarısıyla karşılaştığınızda şu adımları sırayla izleyin:
- Yansımayı ortadan kaldırma - Mümkünse her zaman en iyi seçenek budur.
- DynamicallyAccessedMembers'ı kullanın - Türler biliniyorsa kodu trim uyumlu hale getirin.
- RequiresUnreferencedCode kullan - Gerçekten dinamikse uyumsuzluğu belgele.
- Son çare olarak uyarıları gizleme - Yalnızca kodun güvenli olduğundan eminseniz.
Yaklaşım 1: Yansımayı ortadan kaldırma
En iyi çözüm, mümkün olduğunda tamamen yansımayı önlemektir. Bu, kodunuzu daha hızlı ve tamamen kırpma uyumlu hale getirir.
Derleme zamanı generikleri kullanma
Çalışma zamanı türü işlemlerini derleme zamanı genel parametreleriyle değiştirin:
// ❌ Before: Uses reflection
void CreateAndProcess(Type type)
{
var instance = Activator.CreateInstance(type);
// Process instance...
}
// ✅ After: Uses generics
void CreateAndProcess<T>() where T : new()
{
var instance = new T();
// Process instance...
}
Kaynak oluşturucuları kullanma
Modern .NET, yaygın yansıma senaryoları için kaynak oluşturucular sağlar:
- Serileştirme: Yansıma tabanlı serileştiriciler yerine System.Text.Json kaynak oluşturma kullanın
- Yapılandırma: yapılandırma bağlama kaynak oluşturucusunu kullanma
Daha fazla bilgi için bkz . Bilinen kırpma uyumsuzlukları.
Yaklaşım 2: DynamicallyAccessedMembers ile kodu kırpmaya uyumlu hale getirme
Yansıma gerektiğinde ancak derleme zamanında türler bilindiğinde, kodunuzu çalışma zamanı optimizasyon uyumlu hale getirmek için DynamicallyAccessedMembersAttribute kullanın.
Adım adım: Yansıma kullanımına açıklama ekleme
Uyarı üreten bu örneği göz önünde bulundurun:
void PrintMethodNames(Type type)
{
// ⚠️ IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods'
foreach (var method in type.GetMethods())
{
Console.WriteLine(method.Name);
}
}
1. Adım: Hangi yansıma işleminin gerçekleştirildiğini belirleme
Kod, PublicMethods öğesinin korunmasını gerektiren GetMethods() öğesini çağırır.
2. Adım: Parametreye açıklama ekleme
Gerekenleri bildirmek için kesiciye DynamicallyAccessedMembers ekleyin.
void PrintMethodNames(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
{
// ✅ No warning - trimmer knows to preserve public methods
foreach (var method in type.GetMethods())
{
Console.WriteLine(method.Name);
}
}
3. Adım: Arayanların gereksinimi karşıladığından emin olun
Bu yöntem bilinen bir tür ()typeof ile çağrılırken, gereksinim otomatik olarak karşılanır:
// ✅ OK - DateTime's public methods will be preserved
PrintMethodNames(typeof(DateTime));
Adım adım: Çağrı zincirleri aracılığıyla gereksinimleri yayma
Türler birden çok yöntem üzerinden aktığında gereksinimleri yaymalısınız:
void Method1()
{
Method2<DateTime>(); // ⚠️ Warning: Generic parameter needs annotation
}
void Method2<T>()
{
Type t = typeof(T);
Method3(t); // ⚠️ Warning: Argument doesn't satisfy requirements
}
void Method3(Type type)
{
var methods = type.GetMethods(); // ⚠️ Warning: Reflection usage
}
1. Adım: Yansıma kullanımıyla başlayın
Yansımanın gerçekten kullanıldığı yere açıklama ekleme:
void Method3(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
{
var methods = type.GetMethods(); // ✅ Fixed
}
2. Adım: Çağrı zincirini yayma
Çağrı zincirinde geriye doğru çalışın:
void Method2<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>()
{
Type t = typeof(T);
Method3(t); // ✅ Fixed - T is annotated
}
3. Adım: Arama sitesinde doğrulama
void Method1()
{
Method2<DateTime>(); // ✅ Fixed - DateTime's public methods preserved
}
Gereksinimlerin kodda nasıl aktığı hakkında daha fazla bilgi için Trim Analizini Anlama kısmına bakın.
Common DynamicallyAccessedMemberTypes değerleri
Gereken en düşük erişim düzeyini seçin:
| Üye Türü | Ne zaman kullanılır? |
|---|---|
PublicConstructors |
ya Activator.CreateInstance() kullanma ya da GetConstructor() |
PublicMethods |
GetMethod() veya GetMethods() kullanarak |
PublicFields |
GetField() veya GetFields() kullanarak |
PublicProperties |
GetProperty() veya GetProperties() kullanarak (serileştirme) |
PublicEvents |
GetEvent() veya GetEvents() kullanma |
Uyarı
DynamicallyAccessedMemberTypes.All kullanıldığında, hedef türdeki tüm üyeler ve iç içe geçmiş türlerdeki tüm üyeler korunur (ancak bir özelliğin dönüş türündeki üyeler gibi geçişli bağımlılıkları korumaz). Bu, uygulama boyutunu önemli ölçüde artırır. Daha da önemlisi, korunan üyeler erişilebilir hale gelir ve bu da kendi sorunlu kodlarını içerebilecekleri anlamına gelir. Örneğin, korunan bir üye ile RequiresUnreferencedCodeişaretlenmiş bir yöntemi çağırırsa, üye açık bir çağrı yerine yansıma ek açıklaması aracılığıyla tutulduğundan bu uyarı çözümlenemez. Bu basamaklı sorunlardan kaçınmak için gerekli en düşük üye türlerini kullanın.
Yaklaşım 3: RequiresUnreferencedCode ile kodu uyumsuz olarak işaretleme
Kod temel olarak çözümlenebilir hale getirilemediğinde, uyumsuzluğu belgeleme amacıyla kullanın RequiresUnreferencedCodeAttribute .
RequiresUnreferencedCode ne zaman kullanılır?
Şu durumlarda bu özniteliği kullanın:
- Türler dinamik olarak yüklenir: Çalışma zamanında belirlenen stringlerle GetType() kullanımı.
- Derlemeler çalışma zamanında yüklenir: LoadFrom(String) kullanarak.
- Karmaşık yansıma desenleri: Yansıma kullanımı açıklama eklenemeyecek kadar karmaşık.
-
Çalışma zamanı kodu oluşturma: System.Reflection.Emit veya
dynamicanahtar sözcüğünü kullanma.
Adım adım: Uyumsuz yöntemleri işaretleme
1. Adım: Gerçekten uyumsuz kodu tanımlama
Kırpma uyumlu yapılamayan kod örneği:
void LoadPluginByName(string pluginName)
{
// Type name comes from runtime input - trimmer cannot know what types are needed
Type pluginType = Type.GetType(pluginName);
var plugin = Activator.CreateInstance(pluginType);
// Use plugin...
}
2. Adım: RequiresUnreferencedCode özniteliğini ekleme
[RequiresUnreferencedCode("Plugin loading by name is not compatible with trimming. Consider using compile-time plugin registration instead.")]
void LoadPluginByName(string pluginName)
{
Type pluginType = Type.GetType(pluginName);
var plugin = Activator.CreateInstance(pluginType);
// ✅ No warnings inside this method - it's marked as incompatible
}
3. Adım: Arayanlar uyarı alır
void InitializePlugins()
{
// ⚠️ IL2026: Using member 'LoadPluginByName' which has 'RequiresUnreferencedCodeAttribute'
// can break functionality when trimming application code. Plugin loading by name is not
// compatible with trimming. Consider using compile-time plugin registration instead.
LoadPluginByName("MyPlugin");
}
Etkili uyarı iletileri yazma
İyi RequiresUnreferencedCode bir ileti şöyle olmalıdır:
- Hangi işlevselliğin uyumsuz olduğunu belirtme: Kırpma ile çalışmayan özellikler konusunda belirli olun.
- Alternatifler önerin: Geliştiricilere kırpma uyumlu çözümler konusunda rehberlik edin.
- Kısa olun: İletileri kısa ve eyleme dönüştürülebilir tutun.
// ❌ Not helpful
[RequiresUnreferencedCode("Uses reflection")]
// ✅ Helpful - explains problem and suggests alternative
[RequiresUnreferencedCode("Dynamic type loading is not compatible with trimming. Use generic type parameters or source generators instead.")]
Daha uzun rehberlik için bir Url parametre ekleyin:
[RequiresUnreferencedCode(
"Plugin system is not compatible with trimming. See documentation for alternatives.",
Url = "https://docs.example.com/plugin-trimming")]
RequiresUnreferencedCode Yayma
Bir yöntem ile RequiresUnreferencedCodeişaretlenmiş başka bir yöntemi çağırdığında genellikle özniteliğini yaymanız gerekir:
class PluginSystem
{
// Use a constant for consistent messaging
const string PluginMessage = "Plugin system is not compatible with trimming. Use compile-time registration instead.";
[RequiresUnreferencedCode(PluginMessage)]
private void LoadPluginImplementation(string name)
{
// Low-level plugin loading
}
[RequiresUnreferencedCode(PluginMessage)]
public void LoadPlugin(string name)
{
LoadPluginImplementation(name); // ✅ No warning - method is also marked
}
}
Yaygın desenler ve çözümler
Tasarım Deseni: Activator.CreateInstance ile fabrika yöntemleri
// ❌ Before: Produces warning
object CreateInstance(Type type)
{
return Activator.CreateInstance(type);
}
// ✅ After: Trim-compatible
object CreateInstance(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type type)
{
return Activator.CreateInstance(type);
}
Desen: Eklenti sistemleri derlemeleri yüklüyor
// This pattern is fundamentally incompatible with trimming
[RequiresUnreferencedCode("Plugin loading is not compatible with trimming. Consider compile-time plugin registration using source generators.")]
void LoadPluginsFromDirectory(string directory)
{
foreach (var dll in Directory.GetFiles(directory, "*.dll"))
{
Assembly.LoadFrom(dll);
}
}
Desen: Bağımlılık ekleme kapsayıcıları
// Complex DI containers are often incompatible
class Container
{
[RequiresUnreferencedCode("Service resolution uses complex reflection. Consider using source-generated DI or registering services explicitly.")]
public object Resolve(Type serviceType)
{
// Complex reflection to resolve dependencies
}
}
Yaklaşım 4: Uyarıları son çare olarak gösterme
Uyarı
Yalnızca kodun güvenli olduğundan kesinlikle eminseniz kırpma uyarılarını bastırın. Yanlış baskılamalar, kırpmadan sonra çalışma zamanı hatalarına neden olabilir.
Kodun kırpma açısından güvenli olduğunu doğruladığınızda ancak düzelticinin bunu statik olarak kanıtlayamadığı durumlarda kullanın UnconditionalSuppressMessageAttribute .
Gizleme uygun olduğunda
Uyarıları yalnızca şu durumlarda gizler:
- Gerekli tüm kodun (veya diğer mekanizmalar aracılığıyla
DynamicDependency) korunmasını el ile sağladınız. - Kod yolu hiçbir zaman kırpılan senaryolarda yürütülemez.
- Optimize edilmiş uygulamayı kapsamlı bir şekilde test ettiniz.
Uyarıları gizleme
[RequiresUnreferencedCode("Uses reflection")]
void MethodWithReflection() { /* ... */ }
[UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode",
Justification = "All referenced types are manually preserved via DynamicDependency attributes")]
void CallerMethod()
{
MethodWithReflection(); // Warning suppressed
}
Önemli
Kırpma uyarıları için SuppressMessage veya #pragma warning disable kullanmayın. Bunlar yalnızca derleyici için çalışır, ancak derlenmiş derlemede korunmaz. Düzeltici derlenmiş derlemelerde çalışır ve bu gizlemeleri görmez. Her zaman kullanın UnconditionalSuppressMessage.
Gizleme kapsamını en aza indirme
Bastırmaları mümkün olan en küçük kapsama uygulayın. Sorunlu çağrıyı yerel bir işlev içerisine taşıyın.
void ProcessData()
{
InitializeData();
CallReflectionMethod(); // Only this call is suppressed
ProcessResults();
[UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode",
Justification = "Types are preserved via DynamicDependency on ProcessData method")]
void CallReflectionMethod()
{
MethodWithReflection();
}
}
Bu yaklaşım:
- Belirli bir çağrının gizlenmesini netleştirir.
- Kod değişirse diğer uyarıların yanlışlıkla gizlenmesini önler.
- Gerekçeyi gizlenen çağrıya yakın tutar.
Sorun giderme ipuçları
DynamicallyAccessedMembers eklendikten sonra uyarı devam ediyor
Type kaynağından yansıma kullanımına kadar olan çağrı zincirinin tamamını açıklamalarla kaydettiğinizden emin olun.
- Yansımanın nerede kullanıldığını bulun (örneğin
GetMethods()). - Bu yöntemin parametresine açıklama ekleyin.
-
TypeDeğeri tüm yöntem çağrıları boyunca geriye doğru izleyin. - Zincirdeki her parametre, alan veya genel tür parametresine açıklama ekleyin.
Ele alınamayacak kadar çok uyarı var
- Kendi kodunuzla başlayın- önce denetlediğiniz koddaki uyarıları düzeltin.
- Paketlerden gelen uyarıları tek tek görmek için kullanın
TrimmerSingleWarn. - Kırpmanın uygulamanız için uygun olup olmadığını göz önünde bulundurun.
- Çerçeve düzeyindeki sorunlar için Bilinen kırpma uyumsuzluklarını kontrol edin.
Hangi DynamicallyAccessedMemberTypes'ın kullanılacağından emin değilim
Çağrılan yansıma API'sine bakın:
-
GetMethod()/GetMethods()→PublicMethods -
GetProperty()/GetProperties()→PublicProperties -
GetField()/GetFields()→PublicFields -
GetConstructor()/Activator.CreateInstance()PublicParameterlessConstructor→ veyaPublicConstructors -
GetEvent()/GetEvents()→PublicEvents
Uygulama boyutunu en aza indirmek için mümkün olan en dar türü kullanın.
Sonraki Adımlar
- Kırpma analizini anlama - Kırpma uyarılarının arkasındaki temel kavramları öğrenin
- Kitaplıkları kırpma için hazırlama - Kitaplıklarınızı kırpma uyumlu hale getirme
- Kırpma uyarı referansı - Belirli uyarı kodları hakkında ayrıntılı bilgi
- Bilinen uyumsuzluklar - Kırpma ile uyumlu hale getirilemeyen desenler