.NET kitaplıklarını kırpmaya hazırlama
.NET SDK,kırparak bağımsız uygulamaların boyutunu azaltmayı mümkün kılar. Kırpma, kullanılmayan kodu uygulamadan ve bağımlılıklarından kaldırır. Tüm kodlar kırpmayla uyumlu değildir. .NET, kırpılan uygulamaları kesebilecek desenleri algılamak için kırpma analizi uyarıları sağlar. Bu makalede:
- Kitaplıkları kırpma için hazırlamayı açıklar.
- Yaygın kırpma uyarılarını çözümlemeye yönelik öneriler sağlar.
Önkoşullar
.NET 6 SDK veya üzeri.
En güncel kırpma uyarılarını ve çözümleyici kapsamını almak için:
- .NET 8 SDK'sını veya üstünü yükleyin ve kullanın.
- Hedef
net8.0
veya üzeri.
.NET 7 SDK veya üzeri.
En güncel kırpma uyarılarını ve çözümleyici kapsamını almak için:
- .NET 8 SDK'sını veya üstünü yükleyin ve kullanın.
- Hedef
net8.0
veya üzeri.
.NET 8 SDK veya üzeri.
Kitaplık kırpma uyarılarını etkinleştirme
Kitaplıktaki kırpma uyarıları aşağıdaki yöntemlerden biriyle bulunabilir:
- özelliğini kullanarak projeye özgü kırpmayı
IsTrimmable
etkinleştirme. - Kitaplığı kullanan bir kırpma testi uygulaması oluşturma ve test uygulaması için kırpmayı etkinleştirme. Kitaplıktaki tüm API'lere başvurmak gerekmez.
Her iki yaklaşımı da kullanmanızı öneririz. Projeye özgü kırpma kullanışlı bir özelliktir ve bir proje için kırpma uyarılarını gösterir, ancak tüm uyarıları görmek için kırpma uyumlu olarak işaretlenen başvurulara dayanır. Test uygulamasını kırpmak daha fazla iştir, ancak tüm uyarıları gösterir.
Projeye özgü kırpmayı etkinleştirme
Proje dosyasında ayarlayın <IsTrimmable>true</IsTrimmable>
.
<PropertyGroup>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>
MSBuild özelliğini IsTrimmable
derlemeyi "kırpılabilir" olarak işaretleyip true
kırpma uyarılarını etkinleştirir. "Kırpılabilir", proje anlamına gelir:
- Kırpma ile uyumlu olarak kabul edilir.
- Derleme sırasında kırpmayla ilgili uyarılar oluşturmamalıdır. Kırpılmış bir uygulamada kullanıldığında, derlemenin kullanılmayan üyeleri son çıktıda kırpılır.
özelliği, IsTrimmable
bir projeyi ile <IsAotCompatible>true</IsAotCompatible>
AOT uyumlu olarak yapılandırırken varsayılan true
olarak değerini kullanır. Daha fazla bilgi için bkz . AOT uyumluluğu çözümleyicileri.
Projeyi kırpma uyumlu olarak işaretlemeden kırpma uyarıları oluşturmak için yerine <IsTrimmable>true</IsTrimmable>
kullanın<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
.
Test uygulamasıyla tüm uyarıları göster
Bir kitaplığın tüm çözümleme uyarılarını göstermek için, düzeltici kitaplığın ve kitaplığın kullandığı tüm bağımlılıkların uygulanmasını analiz etmelidir.
Kitaplık oluştururken ve yayımlarken:
- Bağımlılıkların uygulamaları kullanılamaz.
- Kullanılabilir başvuru derlemeleri, kırpma ile uyumlu olup olmadığını belirlemek için düzeltici için yeterli bilgiye sahip değildir.
Bağımlılık sınırlamaları nedeniyle kitaplığını ve bağımlılıklarını kullanan bağımsız bir test uygulaması oluşturulmalıdır. Test uygulaması, düzelticinin kırpma uyumsuzluklarıyla ilgili uyarı vermek için gerektirdiği tüm bilgileri içerir:
- Kitaplık kodu.
- Kitaplığın bağımlılıklarından başvurduğunu kod.
Not
Kitaplığın hedef çerçeveye bağlı olarak farklı davranışları varsa kırpmayı destekleyen hedef çerçevelerin her biri için bir kırpma testi uygulaması oluşturun. Örneğin, kitaplık davranışı değiştirmek için gibi #if NET7_0
koşullu derleme kullanıyorsa.
Kırpma testi uygulamasını oluşturmak için:
- Ayrı bir konsol uygulaması projesi oluşturun.
- Kitaplığa bir başvuru ekleyin.
- Aşağıdaki listeyi kullanarak projeyi aşağıda gösterilen projeye benzer şekilde değiştirin:
Kitaplık kırpılabilir olmayan bir TFM'yi (örneğin net472
veya netstandard2.0
) hedeflerse, kırpma testi uygulaması oluşturmanın bir yararı yoktur. Kırpma yalnızca .NET 6 ve üzeri için desteklenir.
<TrimmerDefaultAction>
seçeneğinilink
olarak ayarlayın.- ekleyin
<PublishTrimmed>true</PublishTrimmed>
. - ile
<ProjectReference Include="/Path/To/YourLibrary.csproj" />
kitaplık projesine bir başvuru ekleyin. - Kitaplığı ile
<TrimmerRootAssembly Include="YourLibraryName" />
bir düzeltici kök derlemesi olarak belirtin.TrimmerRootAssembly
kitaplığın her bölümünün analiz edilmesini sağlar. Düzelticiye bu derlemenin bir "kök" olduğunu söyler. "Kök" derlemesi, düzelticinin kitaplıktaki her çağrıyı analiz etmesi ve bu derlemeden kaynaklanan tüm kod yollarında geçiş yaptığı anlamına gelir.
- ekleyin
<PublishTrimmed>true</PublishTrimmed>
. - ile
<ProjectReference Include="/Path/To/YourLibrary.csproj" />
kitaplık projesine bir başvuru ekleyin. - Kitaplığı ile
<TrimmerRootAssembly Include="YourLibraryName" />
bir düzeltici kök derlemesi olarak belirtin.TrimmerRootAssembly
kitaplığın her bölümünün analiz edilmesini sağlar. Düzelticiye bu derlemenin bir "kök" olduğunu söyler. "Kök" derlemesi, düzelticinin kitaplıktaki her çağrıyı analiz etmesi ve bu derlemeden kaynaklanan tüm kod yollarında geçiş yaptığı anlamına gelir.
- ekleyin
<PublishTrimmed>true</PublishTrimmed>
. - ile
<ProjectReference Include="/Path/To/YourLibrary.csproj" />
kitaplık projesine bir başvuru ekleyin. - Kitaplığı ile
<TrimmerRootAssembly Include="YourLibraryName" />
bir düzeltici kök derlemesi olarak belirtin.TrimmerRootAssembly
kitaplığın her bölümünün analiz edilmesini sağlar. Düzelticiye bu derlemenin bir "kök" olduğunu söyler. "Kök" derlemesi, düzelticinin kitaplıktaki her çağrıyı analiz etmesi ve bu derlemeden kaynaklanan tüm kod yollarında geçiş yaptığı anlamına gelir.
.csproj dosyası
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<PublishTrimmed>true</PublishTrimmed>
<!-- Prevent warnings from unused code in dependencies -->
<TrimmerDefaultAction>link</TrimmerDefaultAction>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="path/to/MyLibrary.csproj" />
<!-- Analyze the whole library, even if attributed with "IsTrimmable" -->
<TrimmerRootAssembly Include="MyLibrary" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MyLibrary\MyLibrary.csproj" />
<TrimmerRootAssembly Include="MyLibrary" />
</ItemGroup>
</Project>
Not: Önceki proje dosyasında ,NET 7 kullanırken değerini ile <TargetFramework>net7.0</TargetFramework>
değiştirin<TargetFramework>net8.0</TargetFramework>
.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MyLibrary\MyLibrary.csproj" />
<TrimmerRootAssembly Include="MyLibrary" />
</ItemGroup>
</Project>
Proje dosyası güncelleştirildikten sonra hedef çalışma zamanı tanımlayıcısı (RID) ile çalıştırındotnet publish
.
dotnet publish -c Release -r <RID>
Birden çok kitaplık için önceki deseni izleyin. Aynı anda birden fazla kitaplığın kırpma çözümleme uyarılarını görmek için, bunların tümünü ve TrimmerRootAssembly
öğeleriyle ProjectReference
aynı projeye ekleyin. ile ve öğeleriyle ProjectReference
tüm kitaplıkları aynı projeye eklemek, kök kitaplıklardan herhangi biri bağımlılıkta bir kırpma dostu olmayan API kullanıyorsa bağımlılıklar hakkında uyarır.TrimmerRootAssembly
Yalnızca belirli bir kitaplıkla ilgili uyarıları görmek için yalnızca bu kitaplığa başvurun.
Not: Analiz sonuçları, bağımlılıkların uygulama ayrıntılarına bağlıdır. Bağımlılığın yeni bir sürümüne güncelleştirilmesi analiz uyarılarına neden olabilir:
- Yeni sürümde anlaşılmayan yansıma desenleri eklenip eklenmediğini gösterir.
- API değişikliği olmasa bile.
- Kitaplık ile
PublishTrimmed
kullanıldığında kırpma analizi uyarılarının getirilmesi hataya neden olan bir değişikliktir.
Kırpma uyarılarını çözme
Yukarıdaki adımlar, kırpılmış bir uygulamada kullanıldığında sorunlara neden olabilecek kodla ilgili uyarılar oluşturur. Aşağıdaki örneklerde, bunları düzeltmek için öneriler içeren en yaygın uyarılar gösterilmektedir.
RequiresUnreferencedCode
Belirtilen yöntemin, örneğin aracılığıyla System.Reflectionstatik olarak başvurulmayan koda dinamik erişim gerektirdiğini belirtmek için kullanan [RequiresUnreferencedCode]
aşağıdaki kodu göz önünde bulundurun.
public class MyLibrary
{
public static void MyMethod()
{
// warning IL2026 :
// MyLibrary.MyMethod: Using 'MyLibrary.DynamicBehavior'
// which has [RequiresUnreferencedCode] can break functionality
// when trimming app code.
DynamicBehavior();
}
[RequiresUnreferencedCode(
"DynamicBehavior is incompatible with trimming.")]
static void DynamicBehavior()
{
}
}
Yukarıdaki vurgulanan kod, kitaplığın kırpma ile uyumsuz olarak açıkça açıklama eklenmiş bir yöntemi çağırdığını gösterir. Uyarıdan kurtulmak için çağrısının DynamicBehavior
gerekip gerekmediğini MyMethod
göz önünde bulundurun. Bu durumda, çağıranların MyMethod
[RequiresUnreferencedCode]
uyarı alması için uyarıyı yaydığı arayana MyMethod
açıklama ekleyin:
public class MyLibrary
{
[RequiresUnreferencedCode("Calls DynamicBehavior.")]
public static void MyMethod()
{
DynamicBehavior();
}
[RequiresUnreferencedCode(
"DynamicBehavior is incompatible with trimming.")]
static void DynamicBehavior()
{
}
}
Özniteliği genel API'ye kadar yaydıktan sonra, kitaplığı çağıran uygulamalar:
- Yalnızca kırpılamayan genel yöntemler için uyarı alın.
- gibi
IL2104: Assembly 'MyLibrary' produced trim warnings
uyarılar almayın.
DynamicallyAccessedMembers
public class MyLibrary3
{
static void UseMethods(Type type)
{
// warning IL2070: MyLibrary.UseMethods(Type): 'this' argument does not satisfy
// 'DynamicallyAccessedMemberTypes.PublicMethods' in call to
// 'System.Type.GetMethods()'.
// The parameter 't' of method 'MyLibrary.UseMethods(Type)' doesn't have
// matching annotations.
foreach (var method in type.GetMethods())
{
// ...
}
}
}
Yukarıdaki kodda, UseMethods
gereksinimi olan [DynamicallyAccessedMembers]
bir yansıma yöntemini çağırıyor. Gereksinim, türün genel yöntemlerinin kullanılabilir olduğunu belirtir. parametresine aynı gereksinimi ekleyerek gereksinimi karşılar UseMethods
.
static void UseMethods(
// State the requirement in the UseMethods parameter.
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
{
// ...
}
Artık gereksinimi karşılamayen değerler geçirirse uyarı üretmeye yönelik PublicMethods tüm çağrılarUseMethods
. benzer şekilde [RequiresUnreferencedCode]
, bu tür uyarıları genel API'lere dağıttıktan sonra işiniz biter.
Aşağıdaki örnekte, bilinmeyen bir Tür açıklamalı yöntem parametresine akar. Bilinmeyen Type
bir alandan geliyor:
static Type type;
static void UseMethodsHelper()
{
// warning IL2077: MyLibrary.UseMethodsHelper(Type): 'type' argument does not satisfy
// 'DynamicallyAccessedMemberTypes.PublicMethods' in call to
// 'MyLibrary.UseMethods(Type)'.
// The field 'System.Type MyLibrary::type' does not have matching annotations.
UseMethods(type);
}
Benzer şekilde, burada sorun alanın type
bu gereksinimlere sahip bir parametreye geçirilmesidir. Alana eklenerek [DynamicallyAccessedMembers]
düzeltildi. [DynamicallyAccessedMembers]
, alana uyumsuz değerler atayan kod hakkında uyarır. Bazen bu işlem bir genel API'ye açıklama ekleninceye kadar devam eder ve diğer zamanlarda somut bir tür bu gereksinimlere sahip bir konuma aktığında sona erer. Örneğin:
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
static Type type;
static void UseMethodsHelper()
{
MyLibrary.type = typeof(System.Tuple);
}
Bu durumda, kırpma analizi genel yöntemlerini Tuplekorur ve daha fazla uyarı üretir.
Öneriler
- Mümkün olduğunda yansımadan kaçının . Yansıma kullanırken, kitaplığın yalnızca küçük bir bölümünden ulaşılabilmesi için yansıma kapsamını en aza indirin.
- Mümkün olduğunda kırpma gereksinimlerini statik olarak ifade etmek için ile
DynamicallyAccessedMembers
koda açıklama ekleyin. - Kodu yeniden düzenleyerek ek açıklama eklenebilen çözümlenebilir bir desen izlemesini sağlamayı göz önünde bulundurun
DynamicallyAccessedMembers
- Kod kırpmayla uyumsuz olduğunda, ile açıklama ekleyin
RequiresUnreferencedCode
ve ilgili genel API'lere açıklama ekleninceye kadar bu ek açıklamayı çağıranlara yayın. - Statik analiz tarafından anlaşılmayan bir şekilde yansıma kullanan kod kullanmaktan kaçının. Örneğin, statik oluşturucularda yansımadan kaçınılmalıdır. Statik oluşturucularda statik olarak analiz edilemeyen yansımanın kullanılması, uyarının sınıfın tüm üyelerine yayılmasına neden olur.
- Sanal yöntemlere veya arabirim yöntemlerine açıklama eklemekten kaçının. Sanal veya arabirim yöntemlerine açıklama eklemek için tüm geçersiz kılmaların eşleşen ek açıklamalara sahip olması gerekir.
- Bir API çoğunlukla kırpma uyumsuzsa, API'ye yönelik alternatif kodlama yaklaşımlarının dikkate alınması gerekebilir. Yansıma tabanlı seri hale getiriciler yaygın bir örnektir. Bu gibi durumlarda, daha kolay statik olarak analiz edilen kodlar üretmek için kaynak oluşturucular gibi diğer teknolojileri benimsemeyi göz önünde bulundurun. Örneğin, bkz . System.Text.Json'da kaynak oluşturmayı kullanma
Çözümlenemeyen desenler için uyarıları çözümleme
Mümkün olduğunda ve DynamicallyAccessedMembers
kullanarak [RequiresUnreferencedCode]
kodunuzun amacını ifade ederek uyarıları çözümlemek daha iyidir. Ancak bazı durumlarda, bu özniteliklerle ifade edilemeyen desenler kullanan veya var olan kodu yeniden düzenlemeden kitaplığın kırpılmasını etkinleştirmek isteyebilirsiniz. Bu bölümde, kırpma analizi uyarılarını çözmenin bazı gelişmiş yolları açıklanmaktadır.
Uyarı
Bu teknikler davranışı veya kodunuzu değiştirebilir veya yanlış kullanıldığında çalışma zamanı özel durumlarıyla sonuçlanabilir.
UnconditionalSuppressMessage
Şu kodu göz önünde bulundurun:
- Amaç, ek açıklamalarla ifade edilemiyor.
- Bir uyarı oluşturur, ancak çalışma zamanında gerçek bir sorunu temsil etmez.
Uyarılar gizlenebilir UnconditionalSuppressMessageAttribute. Bu, ile SuppressMessageAttribute
benzerdir, ancak IL'de kalıcıdır ve kırpma analizi sırasında dikkate alınılır.
Uyarı
Uyarıları bastırırken, inceleme ve test ile doğru olduğunu bildiğiniz sabit değerlere göre kodun kırpma uyumluluğunu garanti etmek sizin sorumluluğunuzdadır. Bu ek açıklamalarda dikkatli olun, çünkü bunlar yanlışsa veya kodunuzun sabit değerleri değişirse hatalı kod gizlenebilir.
Örneğin:
class TypeCollection
{
Type[] types;
// Ensure that only types with preserved constructors are stored in the array
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
public Type this[int i]
{
// warning IL2063: TypeCollection.Item.get: Value returned from method
// 'TypeCollection.Item.get' can't be statically determined and may not meet
// 'DynamicallyAccessedMembersAttribute' requirements.
get => types[i];
set => types[i] = value;
}
}
class TypeCreator
{
TypeCollection types;
public void CreateType(int i)
{
types[i] = typeof(TypeWithConstructor);
Activator.CreateInstance(types[i]); // No warning!
}
}
class TypeWithConstructor
{
}
Yukarıdaki kodda, döndürülen Type
öğesinin gereksinimlerini CreateInstance
karşılaması için dizin oluşturucu özelliğine açıklama eklenmiştir. Bu, oluşturucunun tutulmasını TypeWithConstructor
ve çağrısının CreateInstance
uyarı vermemesini sağlar. Dizin oluşturucu ayarlayıcısı ek açıklaması, içinde depolanan tüm türlerin bir oluşturucuya Type[]
sahip olmasını sağlar. Ancak, döndürülen türün oluşturucunun korunduğunu bilmediğinden, çözümleme bunu göremez ve alıcı için bir uyarı üretir.
Gereksinimlerin karşılandığından eminseniz, alıcıya ekleyerek [UnconditionalSuppressMessage]
bu uyarıyı susturabilirsiniz:
class TypeCollection
{
Type[] types;
// Ensure that only types with preserved constructors are stored in the array
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
public Type this[int i]
{
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063",
Justification = "The list only contains types stored through the annotated setter.")]
get => types[i];
set => types[i] = value;
}
}
class TypeCreator
{
TypeCollection types;
public void CreateType(int i)
{
types[i] = typeof(TypeWithConstructor);
Activator.CreateInstance(types[i]); // No warning!
}
}
class TypeWithConstructor
{
}
Yalnızca yansıtılan üyelerin yansımanın görünür hedefleri olmasını sağlayan ek açıklamalar veya kodlar varsa uyarıyı gizlemenin geçerli olduğunu altını çizmek önemlidir. Üyenin bir çağrı, alan veya özellik erişiminin hedefi olması yeterli değildir. Bazen böyle görünebilir, ancak daha fazla kırpma iyileştirmesi eklendikçe bu tür kodlar sonunda kesilmeye bağlıdır. Yansımanın görünür hedefleri olmayan özellikler, alanlar ve yöntemler satır içine alınabilir, adları kaldırılabilir, farklı türlere taşınabilir veya bunlar üzerinde yansıtmayı bozacak şekilde iyileştirilebilir. Bir uyarıyı bastırırken, yalnızca başka bir yerde kırpma çözümleyicisine yansımanın görünür hedefleri olan hedefleri yansıtmak mümkündür.
// Invalid justification and suppression: property being non-reflectively
// used by the app doesn't guarantee that the property will be available
// for reflection. Properties that are not visible targets of reflection
// are already optimized away with Native AOT trimming and may be
// optimized away for non-native deployment in the future as well.
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063",
Justification = "*INVALID* Only need to serialize properties that are used by"
+ "the app. *INVALID*")]
public string Serialize(object o)
{
StringBuilder sb = new StringBuilder();
foreach (var property in o.GetType().GetProperties())
{
AppendProperty(sb, property, o);
}
return sb.ToString();
}
DynamicDependency
[DynamicDependency]
özniteliği, bir üyenin diğer üyelere dinamik bağımlılığı olduğunu belirtmek için kullanılabilir. Bu, özniteliğine sahip üye her tutulduğunda başvuruda bulunulmuş üyelerin tutulmasına neden olur, ancak uyarıları kendi başına sessize almaz. Kırpma analizini kodun yansıma davranışı hakkında bilgilendiren diğer özniteliklerden farklı olarak, [DynamicDependency]
yalnızca diğer üyeleri tutar. Bu, bazı analiz uyarılarını düzeltmek için ile [UnconditionalSuppressMessage]
birlikte kullanılabilir.
Uyarı
Özniteliği yalnızca diğer yaklaşımlar uygun olmadığında son çare olarak kullanın [DynamicDependency]
. veya [DynamicallyAccessedMembers]
kullanarak [RequiresUnreferencedCode]
yansıma davranışını ifade etmek tercih edilir.
[DynamicDependency("Helper", "MyType", "MyAssembly")]
static void RunHelper()
{
var helper = Assembly.Load("MyAssembly").GetType("MyType").GetMethod("Helper");
helper.Invoke(null, null);
}
olmadan DynamicDependency
, kırpma işlemi başka bir yerde başvurulmazsa tamamen kaldırabilir Helper
MyAssembly
veya tamamen kaldırabilir MyAssembly
ve çalışma zamanında olası bir hatayı gösteren bir uyarı üretir. özniteliği, bunun tutulmasını Helper
sağlar.
özniteliği, veya string
aracılığıyla DynamicallyAccessedMemberTypes
tutulacak üyeleri belirtir. Tür ve derleme, öznitelik bağlamında örtük veya özniteliğinde açıkça belirtilir ( Type
türü ve derleme adı için tarafından veya string
s tarafından).
Tür ve üye dizeleri, üye ön eki olmadan C# belge açıklama kimliği dize biçiminin bir çeşitlemesi kullanır. Üye dizesi bildirimde bulunan türün adını içermemelidir ve belirtilen adın tüm üyelerini tutmak için parametreleri atlar. Biçimin bazı örnekleri aşağıdaki kodda gösterilmiştir:
[DynamicDependency("MyMethod()")]
[DynamicDependency("MyMethod(System,Boolean,System.String)")]
[DynamicDependency("MethodOnDifferentType()", typeof(ContainingType))]
[DynamicDependency("MemberName")]
[DynamicDependency("MemberOnUnreferencedAssembly", "ContainingType"
, "UnreferencedAssembly")]
[DynamicDependency("MemberName", "Namespace.ContainingType.NestedType", "Assembly")]
// generics
[DynamicDependency("GenericMethodName``1")]
[DynamicDependency("GenericMethod``2(``0,``1)")]
[DynamicDependency(
"MethodWithGenericParameterTypes(System.Collections.Generic.List{System.String})")]
[DynamicDependency("MethodOnGenericType(`0)", "GenericType`1", "UnreferencedAssembly")]
[DynamicDependency("MethodOnGenericType(`0)", typeof(GenericType<>))]
[DynamicDependency]
özniteliği, bir yöntemin yardımıyla DynamicallyAccessedMembersAttribute
bile çözümlenemiyor yansıma desenleri içerdiği durumlarda kullanılacak şekilde tasarlanmıştır.