Megosztás a következőn keresztül:


.NET-kódtárak előkészítése a vágáshoz

A .NET SDK lehetővé teszi az önálló alkalmazások méretének csökkentését a vágással. A vágás eltávolítja a nem használt kódot az alkalmazásból és annak függőségeiből. Nem minden kód kompatibilis a vágással. A .NET vágáselemzési figyelmeztetéseket biztosít az olyan minták észleléséhez, amelyek megszakíthatják a levágott alkalmazásokat. A cikk tartalma:

Előfeltételek

.NET 6 SDK vagy újabb.

A legfrissebb vágási figyelmeztetések és elemzői lefedettség lekérése:

  • Telepítse és használja a .NET 8 SDK-t vagy újabb verziót.
  • Cél net8.0 vagy újabb.

.NET 7 SDK vagy újabb.

A legfrissebb vágási figyelmeztetések és elemzői lefedettség lekérése:

  • Telepítse és használja a .NET 8 SDK-t vagy újabb verziót.
  • Cél net8.0 vagy újabb.

.NET 8 SDK vagy újabb.

Kódtár vágására vonatkozó figyelmeztetések engedélyezése

A kódtárakban található vágási figyelmeztetések az alábbi módszerek egyikével találhatók:

  • Projektspecifikus vágás engedélyezése a IsTrimmable tulajdonság használatával.
  • Olyan vágási tesztalkalmazás létrehozása, amely a kódtárat használja, és engedélyezi a vágást a tesztalkalmazáshoz. Nem szükséges a kódtár összes API-jára hivatkozni.

Javasoljuk, hogy mindkét módszert használja. A projektspecifikus vágás kényelmes, és egy projektre vonatkozó vágási figyelmeztetéseket jelenít meg, de a jelöléssel kompatibilis hivatkozásokra támaszkodik az összes figyelmeztetés megjelenítéséhez. A tesztalkalmazások levágása több munkát jelent, de minden figyelmeztetést jelez.

Projektspecifikus vágás engedélyezése

Állítsa be <IsTrimmable>true</IsTrimmable> a projektfájlban.

<PropertyGroup>
    <IsTrimmable>true</IsTrimmable>
</PropertyGroup>

Az MSBuild tulajdonság IsTrimmable beállítása úgy, hogy true a szerelvény "vághatóként" legyen megjelölve, és engedélyezi a vágási figyelmeztetéseket. A "vágható" a projekt:

  • A vágással kompatibilisnek tekinthető.
  • Nem szabad vágással kapcsolatos figyelmeztetéseket generálni a létrehozáskor. Ha egy levágott alkalmazásban használják, a szerelvény nem használt tagjait a végső kimenetben vágja le.

A IsTrimmable tulajdonság alapértelmezés szerint true AOT-kompatibilisként <IsAotCompatible>true</IsAotCompatible>konfigurál egy projektet. További információ: AOT-kompatibilitási elemzők.

Ha vágási figyelmeztetéseket szeretne létrehozni a projekt vágáskompatibilisként való megjelölése nélkül, használja ahelyett<IsTrimmable>true</IsTrimmable>, hogy <EnableTrimAnalyzer>true</EnableTrimAnalyzer> a .

Az összes figyelmeztetés megjelenítése tesztalkalmazással

A tár összes elemzési figyelmeztetésének megjelenítéséhez a vágónak elemeznie kell a tár és a tár által használt összes függőség implementációját.

Könyvtár létrehozásakor és közzétételekor:

  • A függőségek implementációi nem érhetők el.
  • A rendelkezésre álló referenciaszerelvények nem rendelkeznek elegendő információval a vágóhoz annak megállapításához, hogy kompatibilisek-e a vágással.

A függőségi korlátozások miatt létre kell hozni egy önálló tesztalkalmazást, amely a kódtárat és annak függőségeit használja. A tesztalkalmazás tartalmazza az összes információt, amelyhez a vágónak figyelmeztetést kell kiadnia a vágási inkompatibilitásokra vonatkozóan:

  • A kódtár kódja.
  • Az a kód, amelyet a kódtár a függőségeiből hivatkozik.

Feljegyzés

Ha a kódtár működése a célkerettől függően eltérő, hozzon létre egy vágási tesztalkalmazást a vágást támogató cél keretrendszerekhez. Ha például a kódtár feltételes fordítást használ, például #if NET7_0 megváltoztatja a viselkedést.

A vágási tesztalkalmazás létrehozása:

  • Hozzon létre egy külön konzolalkalmazás-projektet.
  • Adjon hozzá egy hivatkozást a tárhoz.
  • Módosítsa a projektet az alábbi listával az alábbi projekthez hasonlóan:

Ha a kódtár olyan TFM-et céloz meg, amely például nem vágható le, net472netstandard2.0akkor nincs előnye a vágási tesztalkalmazások létrehozásának. A vágás csak a .NET 6-os és újabb verzióiban támogatott.

  • Állítsa a <TrimmerDefaultAction> elemet link értékre.
  • Hozzáadás <PublishTrimmed>true</PublishTrimmed>.
  • Hivatkozás hozzáadása a tárprojekthez a következővel <ProjectReference Include="/Path/To/YourLibrary.csproj" />: .
  • Adja meg a kódtárat vágógyökér-szerelvényként a következővel <TrimmerRootAssembly Include="YourLibraryName" />: .
    • TrimmerRootAssembly biztosítja, hogy a kódtár minden része elemezve legyen. Azt mondja a vágónak, hogy ez a szerelvény egy "gyökér". A "gyökér" szerelvény azt jelenti, hogy a vágó elemzi a kódtár minden hívását, és bejárja az adott szerelvényből származó összes kód elérési útját.
  • Hozzáadás <PublishTrimmed>true</PublishTrimmed>.
  • Hivatkozás hozzáadása a tárprojekthez a következővel <ProjectReference Include="/Path/To/YourLibrary.csproj" />: .
  • Adja meg a kódtárat vágógyökér-szerelvényként a következővel <TrimmerRootAssembly Include="YourLibraryName" />: .
    • TrimmerRootAssembly biztosítja, hogy a kódtár minden része elemezve legyen. Azt mondja a vágónak, hogy ez a szerelvény egy "gyökér". A "gyökér" szerelvény azt jelenti, hogy a vágó elemzi a kódtár minden hívását, és bejárja az adott szerelvényből származó összes kód elérési útját.
  • Hozzáadás <PublishTrimmed>true</PublishTrimmed>.
  • Hivatkozás hozzáadása a tárprojekthez a következővel <ProjectReference Include="/Path/To/YourLibrary.csproj" />: .
  • Adja meg a kódtárat vágógyökér-szerelvényként a következővel <TrimmerRootAssembly Include="YourLibraryName" />: .
    • TrimmerRootAssembly biztosítja, hogy a kódtár minden része elemezve legyen. Azt mondja a vágónak, hogy ez a szerelvény egy "gyökér". A "gyökér" szerelvény azt jelenti, hogy a vágó elemzi a kódtár minden hívását, és bejárja az adott szerelvényből származó összes kód elérési útját.

.csproj fájl

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.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>

Megjegyzés: Az előző projektfájlban a .NET 7 használata esetén cserélje le a következőre<TargetFramework>net7.0</TargetFramework><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>

A projektfájl frissítése után futtassa dotnet publish a cél futtatókörnyezet azonosítójával (RID) együtt.

dotnet publish -c Release -r <RID>

Kövesse az előző mintát több kódtár esetében. Ha egyszerre több tárra vonatkozó vágáselemzési figyelmeztetéseket szeretne látni, vegye fel őket ugyanabba a projektbe, mint az ProjectReference elemeket.TrimmerRootAssembly Ha az összes kódtárat hozzáadja ugyanahhoz a projekthez, és TrimmerRootAssembly az elemek figyelmeztetnek a függőségekre, ha a gyökérkönyvtárak valamelyike nem barátkozó API-t használ egy függőségben.ProjectReference Ha olyan figyelmeztetéseket szeretne látni, amelyeknek csak egy adott tárhoz kell tartoznia, hivatkozzon csak erre a tárra.

Megjegyzés: Az elemzés eredményei a függőségek implementálási részleteitől függnek. A függőségek új verziójára való frissítés elemzési figyelmeztetéseket eredményezhet:

  • Ha az új verzió nem értelmezhető tükröződési mintákat adott hozzá.
  • Még akkor is, ha nem történt API-módosítás.
  • A vágáselemzési figyelmeztetések bevezetése kompatibilitástörő változás a kódtár használata esetén PublishTrimmed.

Vágási figyelmeztetések feloldása

Az előző lépések olyan kódra vonatkozó figyelmeztetéseket eredményeznek, amelyek problémákat okozhatnak a levágott alkalmazásokban való használat során. Az alábbi példák a leggyakoribb figyelmeztetéseket mutatják be a javításukra vonatkozó javaslatokkal.

RequiresUnreferencedCode

Vegye figyelembe a következő kódot, amely [RequiresUnreferencedCode] azt jelzi, hogy a megadott metódus dinamikus hozzáférést igényel a statikusan nem hivatkozott kódhoz, például a következőn keresztül System.Reflection.

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()
    {
    }
}

Az előző kiemelt kód azt jelzi, hogy a kódtár olyan metódust hív meg, amely kifejezetten nem kompatibilis a vágással. A figyelmeztetés eltávolításához fontolja meg, hogy hívnia DynamicBehaviorkell-eMyMethod. Ha igen, jegyzetelje meg a hívót MyMethod[RequiresUnreferencedCode] , amellyel propagálja a figyelmeztetést, hogy a hívók MyMethod ehelyett figyelmeztetést kapnak:

public class MyLibrary
{
    [RequiresUnreferencedCode("Calls DynamicBehavior.")]
    public static void MyMethod()
    {
        DynamicBehavior();
    }

    [RequiresUnreferencedCode(
        "DynamicBehavior is incompatible with trimming.")]
    static void DynamicBehavior()
    {
    }
}

Miután propagálta az attribútumot egészen a nyilvános API-ig, a kódtárat hívó alkalmazások:

  • Csak olyan nyilvános metódusokra kapjon figyelmeztetést, amelyek nem vághatók le.
  • Ne kapjon olyan figyelmeztetéseket, mint a IL2104: Assembly 'MyLibrary' produced trim warnings.

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())
        {
            // ...
        }
    }
}

Az előző kódban egy olyan tükröződési metódust hív meg, UseMethods amelynek követelménye [DynamicallyAccessedMembers] van. A követelmény azt állítja, hogy a típus nyilvános módszerei elérhetők. A követelmény teljesítéséhez vegye fel ugyanazt a követelményt a paraméterhez UseMethods.

static void UseMethods(
   // State the requirement in the UseMethods parameter.
   [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
{
    // ...
}

Most minden hívás UseMethods figyelmeztetést eredményez, ha olyan értékeket adnak át, amelyek nem felelnek meg a PublicMethods követelménynek. [RequiresUnreferencedCode]Ehhez hasonlóan, miután propagálta az ilyen figyelmeztetéseket a nyilvános API-kra, már elkészült.

Az alábbi példában egy ismeretlen típus áramlik a jegyzetekkel ellátott metódusparaméterbe. Az ismeretlen Type egy mezőből származik:

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

Itt is az a probléma, hogy a mező type egy paraméterbe kerül ezekkel a követelményekkel. A mezőhöz való hozzáadással [DynamicallyAccessedMembers] javítva van. [DynamicallyAccessedMembers] olyan kódra figyelmeztet, amely inkompatibilis értékeket rendel a mezőhöz. Előfordulhat, hogy ez a folyamat addig folytatódik, amíg a nyilvános API-t nem jegyzetelik, máskor pedig akkor fejeződik be, amikor egy konkrét típus ilyen követelményekkel rendelkező helyre kerül. Példa:

[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
static Type type;

static void UseMethodsHelper()
{
    MyLibrary.type = typeof(System.Tuple);
}

Ebben az esetben a vágáselemzés megtartja Tuplea nyilvános metódusokat, és további figyelmeztetéseket eredményez.

Ajánlások

  • Ha lehetséges, kerülje a tükröződést. Tükröződés használata esetén minimalizálja a tükröződési hatókört, hogy csak a tár egy kis részéből legyen elérhető.
  • Ha lehetséges, fűzze hozzá a DynamicallyAccessedMembers kódot a vágási követelmények statikus kifejezéséhez.
  • Fontolja meg a kód átrendezését, hogy egy elemezhető mintát kövessen, amely megjegyzésekkel DynamicallyAccessedMembers
  • Ha a kód nem kompatibilis a vágással, jegyzetelje meg RequiresUnreferencedCode és propagálja ezt a jegyzetet a hívónak, amíg a megfelelő nyilvános API-k nem lesznek széljegyzetek.
  • Ne használjon olyan kódot, amely a statikus elemzés által nem értelmezhető módon használja a tükröződést. Kerülni kell például a statikus konstruktorok tükröződését. A statikus konstruktorokban statikusan nem elemezhető tükröződés esetén a figyelmeztetés az osztály minden tagjára propagálást eredményez.
  • Kerülje a virtuális metódusok vagy felületi metódusok megjegyzését. A virtuális vagy felületi metódusok széljegyzetezéséhez minden felülbíráláshoz egyező széljegyzetek szükségesek.
  • Ha egy API többnyire nem kompatibilis, előfordulhat, hogy figyelembe kell venni az API alternatív kódolási megközelítéseit. Gyakori példa a tükröződésalapú szerializálók. Ezekben az esetekben fontolja meg más technológiák, például forrásgenerátorok használatát, hogy könnyebben statikusan elemezhető kódot állítsunk elő. Lásd például a forráslétrehozás használatát a System.Text.Jsonban

Nem elemezhető mintákra vonatkozó figyelmeztetések feloldása

Jobb, ha a figyelmeztetéseket úgy oldja meg, hogy kifejezi a kód szándékát a használatával [RequiresUnreferencedCode] és DynamicallyAccessedMembers lehetőség szerint. Bizonyos esetekben azonban érdemes lehet engedélyezni egy olyan kódtár vágását, amely olyan mintákat használ, amelyek nem fejezhetők ki ezekkel az attribútumokkal, vagy a meglévő kód újrabontása nélkül. Ez a szakasz a vágáselemzési figyelmeztetések megoldásának néhány speciális módját ismerteti.

Figyelmeztetés

Ezek a technikák megváltoztathatják a viselkedést vagy a kódot, vagy futásidejű kivételeket eredményezhetnek, ha helytelenül használják őket.

Feltétel nélküliSuppressMessage

Fontolja meg a következő kódot:

  • A szándék nem fejezhető ki a széljegyzetekkel.
  • Figyelmeztetést generál, de futásidőben nem jelent valós problémát.

A figyelmeztetések mellőzhetők UnconditionalSuppressMessageAttribute. Ez hasonló SuppressMessageAttribute, de az IL-ben megmarad, és a vágáselemzés során tiszteletben tartja.

Figyelmeztetés

A figyelmeztetések mellőzése esetén Ön a felelős a kód vágási kompatibilitásának garantálásáért az olyan invariánsok alapján, amelyekről ön tudja, hogy igaz az ellenőrzés és a tesztelés során. Ezekkel a széljegyzetekkel óvatosan járjon el, mert ha helytelenek, vagy ha a kód módosításakor módosulnak, előfordulhat, hogy helytelen kódot rejtenek el.

Példa:

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
{
}

Az előző kódban az indexelő tulajdonság megjegyzést kapott, hogy a visszaadott Type érték megfeleljen a következő követelményeinek CreateInstance: . Ez biztosítja, hogy a TypeWithConstructor konstruktor megmaradjon, és hogy a hívás CreateInstance ne figyelmeztesse. Az indexelő-beállítási széljegyzet biztosítja, hogy a Type[] benne tárolt típusok konstruktorokkal rendelkezzenek. Az elemzés azonban nem látja ezt, és figyelmeztetést ad a getter számára, mert nem tudja, hogy a visszaadott típus konstruktora megőrződött.

Ha biztos abban, hogy teljesülnek a követelmények, elhallgattathatja ezt a figyelmeztetést a getterhez való hozzáadással [UnconditionalSuppressMessage] :

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
{
}

Fontos hangsúlyozni, hogy csak akkor érvényes a figyelmeztetés mellőzése, ha vannak olyan széljegyzetek vagy kódok, amelyek biztosítják, hogy a tükrözött tagok látható célként szolgálnak a tükröződés számára. Nem elegendő, hogy a tag egy hívás, mező vagy tulajdonság hozzáférésének célpontja volt. Néha úgy tűnhet, hogy ez a helyzet, de az ilyen kódnak előbb-utóbb megszakadnia kell, mivel további vágási optimalizálásokat adnak hozzá. A nem látható tükröződési célokat tartalmazó tulajdonságok, mezők és metódusok beágyazottak lehetnek, eltávolíthatják a nevüket, áthelyezhetők különböző típusokra, vagy más módon optimalizálhatók úgy, hogy az tükrözze őket. Figyelmeztetés elnyomásakor csak olyan célokra lehet visszatükrözni, amelyek máshol látható tükröződési célpontok voltak a vágáselemző számára.

// 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

Az [DynamicDependency] attribútum azt jelzi, hogy egy tag dinamikus függőségben van a többi taggal. Ez azt eredményezi, hogy a hivatkozott tagok mindig megmaradnak, amikor az attribútummal rendelkező tag megmarad, de önmagában nem hallgat el figyelmeztetéseket. A többi attribútumtól eltérően, amelyek tájékoztatják a vágáselemzést a kód tükröződési viselkedéséről, [DynamicDependency] csak a többi tagot tartja meg. Ez együtt használható egyes elemzési [UnconditionalSuppressMessage] figyelmeztetések kijavításához.

Figyelmeztetés

Csak akkor használjon [DynamicDependency] attribútumot végső megoldásként, ha a többi megközelítés nem járható út. Jobb, ha a tükröződési viselkedést a vagy [DynamicallyAccessedMembers]a [RequiresUnreferencedCode] .

[DynamicDependency("Helper", "MyType", "MyAssembly")]
static void RunHelper()
{
    var helper = Assembly.Load("MyAssembly").GetType("MyType").GetMethod("Helper");
    helper.Invoke(null, null);
}

A DynamicDependencynélkül a vágás eltávolítható HelperMyAssembly vagy teljesen eltávolítható MyAssembly , ha máshol nem hivatkoznak rá, és olyan figyelmeztetést eredményez, amely futásidőben lehetséges meghibásodást jelez. Az attribútum gondoskodik róla, hogy Helper megtartsa azt.

Az attribútum megadja a megtartandó tagokat egy vagy többen string keresztül DynamicallyAccessedMemberTypes. A típus és a szerelvény implicit módon van megadva az attribútumkörnyezetben, vagy explicit módon meg van adva az attribútumban ( Typea típus és a szerelvény neve szerint , vagy s szerint string).

A típus- és tagsztringek a C#-dokumentáció megjegyzésazonosító sztringformátumának egy változatát használják a tagelőtag előtag nélkül. A tagsztring nem tartalmazhatja a deklarálási típus nevét, és kihagyhatja a paramétereket a megadott név összes tagjának megtartásához. Néhány példa a formátumra az alábbi kódban látható:

[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<>))]

Az [DynamicDependency] attribútum olyan esetekben használható, amikor egy metódus olyan tükröződési mintákat tartalmaz, amelyek még a segítségével DynamicallyAccessedMembersAttributesem elemezhetők.