Przygotowywanie bibliotek platformy .NET do przycinania

Zestaw SDK platformy .NET umożliwia zmniejszenie rozmiaru aplikacji samodzielnych przez przycinanie. Przycinanie usuwa nieużywany kod z aplikacji i jej zależności. Nie wszystkie kody są zgodne z przycinaniem. Platforma .NET udostępnia ostrzeżenia analizy przycinania w celu wykrywania wzorców, które mogą spowodować przerwanie przycinanych aplikacji. W tym artykule:

Wymagania wstępne

Zestaw .NET 6 SDK lub nowszy.

Aby uzyskać najbardziej aktualne ostrzeżenia dotyczące przycinania i pokrycia analizatora:

  • Zainstaluj i użyj zestawu .NET 8 SDK lub nowszego.
  • Element docelowy net8.0 lub nowszy.

Zestaw .NET 7 SDK lub nowszy.

Aby uzyskać najbardziej aktualne ostrzeżenia dotyczące przycinania i pokrycia analizatora:

  • Zainstaluj i użyj zestawu .NET 8 SDK lub nowszego.
  • Element docelowy net8.0 lub nowszy.

Zestaw .NET 8 SDK lub nowszy.

Włączanie ostrzeżeń dotyczących przycinania biblioteki

Ostrzeżenia dotyczące przycinania w bibliotece można znaleźć przy użyciu jednej z następujących metod:

  • Włączanie przycinania specyficznego IsTrimmable dla projektu przy użyciu właściwości .
  • Tworzenie aplikacji testowej przycinania korzystającej z biblioteki i włączania przycinania aplikacji testowej. Nie trzeba odwoływać się do wszystkich interfejsów API w bibliotece.

Zalecamy użycie obu metod. Przycinanie specyficzne dla projektu jest wygodne i pokazuje ostrzeżenia dotyczące przycinania dla jednego projektu, ale opiera się na odwołaniach oznaczonych jako zgodne z przycinaniem, aby wyświetlić wszystkie ostrzeżenia. Przycinanie aplikacji testowej jest bardziej pracowite, ale pokazuje wszystkie ostrzeżenia.

Włączanie przycinania specyficznego dla projektu

Ustaw <IsTrimmable>true</IsTrimmable> w pliku projektu.

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

Ustawienie właściwości IsTrimmable MSBuild w celu oznaczania true zestawu jako "trimmable" i włącza ostrzeżenia przycinania. "Przycinanie" oznacza projekt:

  • Jest uznawany za zgodny z przycinaniem.
  • Nie należy generować ostrzeżeń dotyczących przycinania podczas kompilowania. W przypadku użycia w przyciętej aplikacji zestaw ma nieużywane elementy członkowskie przycięte w końcowych danych wyjściowych.

Właściwość IsTrimmable jest domyślnie ustawiona true podczas konfigurowania projektu jako zgodnego z funkcją AOT.<IsAotCompatible>true</IsAotCompatible> Aby uzyskać więcej informacji, zobacz Analizatory zgodności AOT.

Aby wygenerować ostrzeżenia dotyczące przycinania bez oznaczania projektu jako zgodnego z wykończeniami, należy użyć <EnableTrimAnalyzer>true</EnableTrimAnalyzer> zamiast <IsTrimmable>true</IsTrimmable>.

Pokaż wszystkie ostrzeżenia za pomocą aplikacji testowej

Aby wyświetlić wszystkie ostrzeżenia analizy dla biblioteki, trymer musi przeanalizować implementację biblioteki i wszystkich zależności używanych przez bibliotekę.

Podczas kompilowania i publikowania biblioteki:

  • Implementacje zależności nie są dostępne.
  • Dostępne zestawy referencyjne nie mają wystarczającej ilości informacji dla trymeru, aby określić, czy są one zgodne z przycinaniem.

Ze względu na ograniczenia zależności należy utworzyć samodzielną aplikację testową korzystającą z biblioteki i jej zależności. Aplikacja testowa zawiera wszystkie informacje wymagane przez trymer do ostrzeżenia dotyczącego niezgodności przycinania w:

  • Kod biblioteki.
  • Kod, do którego odwołuje się biblioteka, od jej zależności.

Uwaga

Jeśli biblioteka ma inne zachowanie w zależności od platformy docelowej, utwórz aplikację testową przycinania dla każdej z platform docelowych, które obsługują przycinanie. Jeśli na przykład biblioteka używa kompilacji warunkowej, takiej jak #if NET7_0 zmiana zachowania.

Aby utworzyć aplikację testowej przycinania:

  • Utwórz oddzielny projekt aplikacji konsolowej.
  • Dodaj odwołanie do biblioteki.
  • Zmodyfikuj projekt podobny do przedstawionego poniżej, korzystając z następującej listy:

Jeśli biblioteka jest przeznaczona dla programu TFM, który nie jest możliwy do przycinania, na przykład net472 lub netstandard2.0, nie ma korzyści z utworzenia aplikacji testowej przycinania. Przycinanie jest obsługiwane tylko dla platformy .NET 6 i nowszych.

  • Ustaw wartość opcji <TrimmerDefaultAction> na link.
  • Dodaj <PublishTrimmed>true</PublishTrimmed>element .
  • Dodaj odwołanie do projektu biblioteki za pomocą polecenia <ProjectReference Include="/Path/To/YourLibrary.csproj" />.
  • Określ bibliotekę jako zestaw główny trimmer za pomocą polecenia <TrimmerRootAssembly Include="YourLibraryName" />.
    • TrimmerRootAssembly gwarantuje, że każda część biblioteki jest analizowana. Informuje on trymer, że ten zestaw jest "katalogiem głównym". Zestaw "główny" oznacza, że trymer analizuje każde wywołanie w bibliotece i przechodzi przez wszystkie ścieżki kodu pochodzące z tego zestawu.
  • Dodaj <PublishTrimmed>true</PublishTrimmed>element .
  • Dodaj odwołanie do projektu biblioteki za pomocą polecenia <ProjectReference Include="/Path/To/YourLibrary.csproj" />.
  • Określ bibliotekę jako zestaw główny trimmer za pomocą polecenia <TrimmerRootAssembly Include="YourLibraryName" />.
    • TrimmerRootAssembly gwarantuje, że każda część biblioteki jest analizowana. Informuje on trymer, że ten zestaw jest "katalogiem głównym". Zestaw "główny" oznacza, że trymer analizuje każde wywołanie w bibliotece i przechodzi przez wszystkie ścieżki kodu pochodzące z tego zestawu.
  • Dodaj <PublishTrimmed>true</PublishTrimmed>element .
  • Dodaj odwołanie do projektu biblioteki za pomocą polecenia <ProjectReference Include="/Path/To/YourLibrary.csproj" />.
  • Określ bibliotekę jako zestaw główny trimmer za pomocą polecenia <TrimmerRootAssembly Include="YourLibraryName" />.
    • TrimmerRootAssembly gwarantuje, że każda część biblioteki jest analizowana. Informuje on trymer, że ten zestaw jest "katalogiem głównym". Zestaw "główny" oznacza, że trymer analizuje każde wywołanie w bibliotece i przechodzi przez wszystkie ścieżki kodu pochodzące z tego zestawu.

Plik csproj

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

Uwaga: w poprzednim pliku projektu w przypadku korzystania z platformy .NET 7 zastąp ciąg <TargetFramework>net8.0</TargetFramework> .<TargetFramework>net7.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>

Po zaktualizowaniu pliku projektu uruchom polecenie dotnet publish z docelowym identyfikatorem środowiska uruchomieniowego (RID).

dotnet publish -c Release -r <RID>

Postępuj zgodnie z powyższym wzorcem dla wielu bibliotek. Aby wyświetlić ostrzeżenia dotyczące analizy przycinania dla więcej niż jednej biblioteki jednocześnie, dodaj je wszystkie do tego samego projektu co ProjectReference elementy i TrimmerRootAssembly . Dodanie wszystkich bibliotek do tego samego projektu z elementami ProjectReference i ostrzega o zależnościach, jeśli którakolwiek z bibliotek głównych korzysta z interfejsu API niezagodzonego przycinania w TrimmerRootAssembly zależności. Aby wyświetlić ostrzeżenia, które mają związek tylko z określoną biblioteką, należy odwołać się tylko do tej biblioteki.

Uwaga: wyniki analizy zależą od szczegółów implementacji zależności. Aktualizacja do nowej wersji zależności może spowodować wprowadzenie ostrzeżeń analizy:

  • Jeśli nowa wersja dodała niezrozumiane wzorce odbicia.
  • Nawet jeśli nie nastąpiły żadne zmiany interfejsu API.
  • Wprowadzenie ostrzeżeń dotyczących analizy przycinania to zmiana powodująca niezgodność, gdy biblioteka jest używana z PublishTrimmedprogramem .

Rozwiązywanie problemów z ostrzeżeniami dotyczącymi przycinania

Powyższe kroki generują ostrzeżenia dotyczące kodu, które mogą powodować problemy w przypadku użycia w przyciętej aplikacji. W poniższych przykładach przedstawiono najbardziej typowe ostrzeżenia z zaleceniami dotyczącymi ich naprawiania.

RequiresUnreferencedCode

Rozważ poniższy kod, który używa [RequiresUnreferencedCode] metody , aby wskazać, że określona metoda wymaga dynamicznego dostępu do kodu, do którego nie odwołuje się statycznie, na przykład za pośrednictwem System.Reflectionmetody .

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

Powyższy wyróżniony kod wskazuje, że biblioteka wywołuje metodę, która została jawnie oznaczona jako niezgodna z przycinaniem. Aby pozbyć się ostrzeżenia, rozważ, czy MyMethod należy wywołać metodę DynamicBehavior. Jeśli tak, dodaj adnotację do obiektu wywołującego MyMethod , za [RequiresUnreferencedCode] pomocą którego propaguje ostrzeżenie, aby zamiast tego osoby wywołujące MyMethod uzyskać ostrzeżenie:

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

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

Po propagacji atrybutu aż do publicznego interfejsu API aplikacje wywołujące bibliotekę:

  • Otrzymuj ostrzeżenia tylko dla metod publicznych, które nie są możliwe do przycinania.
  • Nie otrzymuj ostrzeżeń, takich jak IL2104: Assembly 'MyLibrary' produced trim warnings.

DynamiczneaccessedMembers

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

W poprzednim kodzie wywołuje metodę odbicia, UseMethods która ma [DynamicallyAccessedMembers] wymaganie. Wymaganie wskazuje, że dostępne są metody publiczne typu. Spełnij wymaganie, dodając to samo wymaganie do parametru .UseMethods

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

Teraz wszystkie wywołania do UseMethods generowania ostrzeżeń, jeśli przekazują wartości, które nie spełniają PublicMethods wymagań. Podobnie jak w przypadku [RequiresUnreferencedCode]propagacji takich ostrzeżeń do publicznych interfejsów API, wszystko będzie gotowe.

W poniższym przykładzie nieznany typ przepływa do parametru metody z adnotacjami. Nieznany Type element pochodzi z pola:

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

Podobnie problem polega na tym, że pole type jest przekazywane do parametru z tymi wymaganiami. Naprawiono to przez dodanie [DynamicallyAccessedMembers] do pola. [DynamicallyAccessedMembers] ostrzega o kodzie, który przypisuje niezgodne wartości do pola. Czasami ten proces jest kontynuowany, dopóki publiczny interfejs API nie zostanie oznaczony adnotacją, a innym razem kończy się, gdy konkretny typ przechodzi do lokalizacji z tymi wymaganiami. Na przykład:

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

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

W tym przypadku analiza przycinania utrzymuje publiczne metody Tuple, i generuje dalsze ostrzeżenia.

Zalecenia

  • Unikaj odbicia, jeśli to możliwe. W przypadku korzystania z odbicia zminimalizuj zakres odbicia, aby był osiągalny tylko z niewielkiej części biblioteki.
  • Dodaj adnotację do kodu , DynamicallyAccessedMembers aby statycznie wyrazić wymagania dotyczące przycinania, jeśli to możliwe.
  • Rozważ reorganizację kodu, aby postępować zgodnie z analizowanym wzorcem, za pomocą którego można dodawać adnotacje DynamicallyAccessedMembers
  • Gdy kod jest niezgodny z przycinaniem, dodaj do niego RequiresUnreferencedCode adnotację i propaguj tę adnotację do elementów wywołujących, dopóki odpowiednie publiczne interfejsy API nie zostaną oznaczone adnotacjami.
  • Unikaj używania kodu, który używa odbicia w sposób niezrozumiały przez analizę statyczną. Na przykład należy unikać odbicia w konstruktorach statycznych. Użycie statycznie nieanalizowalnego odbicia w konstruktorach statycznych powoduje propagację ostrzeżenia do wszystkich składowych klasy.
  • Unikaj dodawania adnotacji do metod wirtualnych lub metod interfejsu. Dodawanie adnotacji do metod wirtualnych lub interfejsu wymaga, aby wszystkie przesłonięcia miały pasujące adnotacje.
  • Jeśli interfejs API jest w większości niezgodny, może być konieczne rozważenie alternatywnego podejścia kodowania do interfejsu API. Typowym przykładem są serializatory oparte na odbiciu. W takich przypadkach rozważ wdrożenie innych technologii, takich jak generatory źródeł, aby utworzyć kod, który jest łatwiej analizowany statycznie. Na przykład zobacz How to use source generation in System.Text.Json (Jak używać generowania źródła w pliku System.Text.Json)

Rozwiązywanie problemów z ostrzeżeniami dla nieanalizowalnych wzorców

Lepiej jest rozwiązać problemy z ostrzeżeniami, wyrażając intencję kodu przy użyciu instrukcji [RequiresUnreferencedCode] i DynamicallyAccessedMembers , gdy jest to możliwe. Jednak w niektórych przypadkach może cię zainteresować włączenie przycinania biblioteki, która używa wzorców, których nie można wyrazić za pomocą tych atrybutów lub bez refaktoryzacji istniejącego kodu. W tej sekcji opisano niektóre zaawansowane sposoby rozwiązywania problemów z ostrzeżeniami dotyczącymi analizy przycinania.

Ostrzeżenie

Te techniki mogą zmieniać zachowanie lub kod lub powodować wyjątki czasu wykonywania, jeśli są używane niepoprawnie.

BezwarunkowapressMessage

Rozważ kod, który:

  • Intencji nie można wyrazić adnotacjami.
  • Generuje ostrzeżenie, ale nie reprezentuje rzeczywistego problemu w czasie wykonywania.

Ostrzeżenia można pominąć UnconditionalSuppressMessageAttribute. Jest to podobne do SuppressMessageAttribute, ale jest utrwalane w IL i szanowane podczas analizy przycinania.

Ostrzeżenie

Podczas pomijania ostrzeżeń ponosisz odpowiedzialność za zagwarantowanie zgodności przycinania kodu na podstawie niezmienności, które są prawdziwe przez inspekcję i testowanie. Należy zachować ostrożność w przypadku tych adnotacji, ponieważ jeśli są one nieprawidłowe lub jeśli zmiany kodu są nieprawidłowe, mogą one ukrywać niepoprawny kod.

Na przykład:

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

W poprzednim kodzie właściwość indeksatora została oznaczona adnotacją, tak aby zwrócona Type wartość spełniała wymagania .CreateInstance Gwarantuje to, że TypeWithConstructor konstruktor jest zachowany i że wywołanie CreateInstance polecenia nie ostrzega. Adnotacja ustawiająca indeksatora gwarantuje, że wszystkie typy przechowywane w obiekcie Type[] mają konstruktor. Jednak analiza nie jest w stanie to zobaczyć i generuje ostrzeżenie dla metody getter, ponieważ nie wie, że zwrócony typ ma zachowany konstruktor.

Jeśli masz pewność, że wymagania zostały spełnione, możesz wyciszyć to ostrzeżenie, dodając [UnconditionalSuppressMessage] polecenie getter:

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

Należy podkreślić, że ważne jest, aby pominąć ostrzeżenie tylko wtedy, gdy istnieją adnotacje lub kod, które zapewniają, że odzwierciedlone elementy członkowskie są widocznymi elementami docelowymi odbicia. Nie wystarczy, że element członkowski był elementem docelowym wywołania, pola lub dostępu do właściwości. Może się wydawać, że czasami tak się stanie, ale taki kod jest powiązany z awarią w miarę dodawania większej liczby optymalizacji przycinania. Właściwości, pola i metody, które nie są widocznymi miejscami docelowymi odbicia, mogą być podkreślone, mają usunięte nazwy, zostaną przeniesione do różnych typów lub w inny sposób zoptymalizowane w sposób, który przerywa ich odzwierciedlanie. W przypadku pomijania ostrzeżenia dopuszczalne jest jedynie odzwierciedlinie elementów docelowych, które były widocznymi celami odbicia do analizatora przycinania w innym miejscu.

// 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 (Współzależność dynamiczna)

Atrybut [DynamicDependency] może służyć do wskazania, że element członkowski ma dynamiczną zależność od innych elementów członkowskich. Powoduje to, że przywoływane elementy członkowskie są przechowywane za każdym razem, gdy członek z atrybutem jest przechowywany, ale nie wycisza ostrzeżeń samodzielnie. W przeciwieństwie do innych atrybutów, które informują analizę przycinania o zachowaniu odbicia kodu, [DynamicDependency] zachowuje tylko inne elementy członkowskie. Może to być używane razem z [UnconditionalSuppressMessage] w celu naprawienia niektórych ostrzeżeń analizy.

Ostrzeżenie

Użyj [DynamicDependency] atrybutu tylko w ostateczności, gdy inne podejścia nie są opłacalne. Preferowane jest wyrażenie zachowania odbicia przy użyciu metody [RequiresUnreferencedCode] lub [DynamicallyAccessedMembers].

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

Bez DynamicDependencyfunkcji przycinanie może zostać całkowicie usunięte Helper lub MyAssembly usunięte MyAssembly , jeśli nie odwołuje się do niego w innym miejscu, generując ostrzeżenie wskazujące możliwe niepowodzenie w czasie wykonywania. Atrybut zapewnia, że Helper jest przechowywany.

Atrybut określa elementy członkowskie, które mają być zachowywane za pośrednictwem elementu string lub za pośrednictwem DynamicallyAccessedMemberTypes. Typ i zestaw są niejawne w kontekście atrybutu lub jawnie określone w atrybucie (przez Type, lub przez strings dla typu i nazwy zestawu).

Ciągi typów i składowych używają odmiany formatu ciągu identyfikatora komentarza dokumentacji języka C# bez prefiksu elementu członkowskiego. Ciąg składowy nie powinien zawierać nazwy typu deklarowanego i może pominąć parametry, aby zachować wszystkie elementy członkowskie określonej nazwy. Niektóre przykłady formatu są wyświetlane w następującym kodzie:

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

Atrybut [DynamicDependency] jest przeznaczony do użycia w przypadkach, gdy metoda zawiera wzorce odbicia, których nie można przeanalizować nawet za pomocą metody DynamicallyAccessedMembersAttribute.