Rezervované atributy: různé

Tyto atributy lze použít na prvky v kódu. Přidávají těmto prvkům sémantické významy. Kompilátor používá tyto sémantické významy ke změně jeho výstupu a nahlášení možných chyb vývojáři, kteří používají váš kód.

Atribut Conditional

ConditionalAtribut provádí provádění metody závislé na identifikátoru předběžného zpracování. ConditionalAtribut je alias pro ConditionalAttribute a lze jej použít pro metodu nebo třídu atributu.

V následujícím příkladu Conditional je použita na metodu pro povolení nebo zakázání zobrazení diagnostických informací specifických pro program:

#define TRACE_ON
using System;
using System.Diagnostics;

namespace AttributeExamples
{
    public class Trace
    {
        [Conditional("TRACE_ON")]
        public static void Msg(string msg)
        {
            Console.WriteLine(msg);
        }
    }

    public class TraceExample
    {
        public static void Main()
        {
            Trace.Msg("Now in Main...");
            Console.WriteLine("Done.");
        }
    }
}

Pokud TRACE_ON identifikátor není definován, výstup trasování se nezobrazí. Prozkoumejte si sami v interaktivním okně.

ConditionalAtribut se často používá s DEBUG identifikátorem pro povolení funkcí trasování a protokolování pro sestavení ladění, ale ne v sestaveních vydaných verzí, jak je znázorněno v následujícím příkladu:

[Conditional("DEBUG")]
static void DebugMethod()
{
}

Když je volána metoda s označením podmíněné, přítomnost nebo absence zadaného symbolu předzpracování určuje, zda kompilátor obsahuje nebo vynechává volání metody. Pokud je symbol definován, volání je zahrnuto; v opačném případě je volání vynecháno. Podmíněná metoda musí být metoda v deklaraci třídy nebo struktury a musí mít void návratový typ. Použití Conditional je čistič, jasnější a méně náchylné k chybám než nadřazené metody uvnitř #if…#endif bloků.

Pokud má metoda více Conditional atributů, kompilátor obsahuje volání metody, pokud je definován jeden nebo více podmíněných symbolů (symboly jsou logicky propojeny pomocí operátoru OR). V následujícím příkladu je přítomna buď, A nebo má B za následek volání metody:

[Conditional("A"), Conditional("B")]
static void DoIfAorB()
{
    // ...
}

Použití Conditional s třídami atributů

ConditionalAtribut lze použít také pro definici třídy atributu. V následujícím příkladu vlastní atribut Documentation přidá pouze informace do metadat, pokud DEBUG je definována.

[Conditional("DEBUG")]
public class DocumentationAttribute : System.Attribute
{
    string text;

    public DocumentationAttribute(string text)
    {
        this.text = text;
    }
}

class SampleClass
{
    // This attribute will only be included if DEBUG is defined.
    [Documentation("This method displays an integer.")]
    static void DoWork(int i)
    {
        System.Console.WriteLine(i.ToString());
    }
}

Atribut Obsolete

ObsoleteAtribut označuje prvek kódu, který již není doporučen pro použití. Použití entity označené jako zastaralé generuje upozornění nebo chybu. ObsoleteAtribut je atribut s jedním použitím a lze jej použít pro libovolnou entitu, která povoluje atributy. Obsolete je alias pro ObsoleteAttribute .

V následujícím příkladu Obsolete je atribut použit pro třídu A a na metodu B.OldMethod . Vzhledem k tomu, že druhý argument konstruktoru atributu použité pro B.OldMethod je nastaven na true , tato metoda způsobí chybu kompilátoru, zatímco použití třídy A bude pouze generovat upozornění. Volání B.NewMethod však negeneruje žádné upozornění nebo chybu. Například když použijete s předchozími definicemi, následující kód vygeneruje dvě upozornění a jednu chybu:

using System;

namespace AttributeExamples
{
    [Obsolete("use class B")]
    public class A
    {
        public void Method() { }
    }

    public class B
    {
        [Obsolete("use NewMethod", true)]
        public void OldMethod() { }

        public void NewMethod() { }
    }

    public static class ObsoleteProgram
    {
        public static void Main()
        {
            // Generates 2 warnings:
            A a = new A();

            // Generate no errors or warnings:
            B b = new B();
            b.NewMethod();

            // Generates an error, compilation fails.
            // b.OldMethod();
        }
    }
}

Řetězec poskytnutý jako první argument konstruktoru atributu se zobrazí jako součást upozornění nebo chyby. Dvě upozornění pro třídu A jsou vygenerována: jedna pro deklaraci odkazu na třídu a druhá pro konstruktor třídy. ObsoleteAtribut se dá použít bez argumentů, ale doporučuje se místo toho vysvětlit, co použít.

V C# 10 můžete použít interpolaci konstantních řetězců a nameof operátor k zajištění shody názvů:

public class B
{
    [Obsolete($"use {nameof(NewMethod)} instead", true)]
    public void OldMethod() { }

    public void NewMethod() { }
}

Atribut AttributeUsage

AttributeUsageAtribut určuje, jak lze použít třídu vlastního atributu. AttributeUsageAttribute je atribut, který použijete pro definice vlastních atributů. AttributeUsageAtribut umožňuje řídit:

  • Který atribut programových prvků může být použit pro. Pokud neomezíte jeho využití, lze atribut použít na některý z následujících prvků programu:
    • Sestavení
    • Modul
    • Pole
    • Událost
    • Metoda
    • Param
    • Vlastnost
    • Vrátit
    • Typ
  • Určuje, zda lze atribut použít pro jeden prvek programu několikrát.
  • Zda jsou atributy děděny odvozenými třídami.

Výchozí nastavení vypadají jako v následujícím příkladu při explicitním použití:

[AttributeUsage(AttributeTargets.All,
                   AllowMultiple = false,
                   Inherited = true)]
class NewAttribute : Attribute { }

V tomto příkladu NewAttribute lze třídu použít pro libovolný podporovaný prvek programu. Dá se ale použít jenom jednou pro každou entitu. Atribut je děděn odvozenými třídami při použití na základní třídu.

AllowMultipleArgumenty a Inherited jsou volitelné, takže následující kód má stejný účinek:

[AttributeUsage(AttributeTargets.All)]
class NewAttribute : Attribute { }

První AttributeUsageAttribute argument musí být jeden nebo více prvků AttributeTargets výčtu. Více cílových typů lze propojit společně s operátorem OR, jak ukazuje následující příklad:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
class NewPropertyOrFieldAttribute : Attribute { }

Počínaje jazykem C# 7,3 atributy lze použít buď na vlastnost, nebo na pole pro zálohování pro automaticky implementovanou vlastnost. Atribut se vztahuje na vlastnost, pokud nezadáte field specifikátor v atributu. Obě jsou uvedeny v následujícím příkladu:

class MyClass
{
    // Attribute attached to property:
    [NewPropertyOrField]
    public string Name { get; set; } = string.Empty;

    // Attribute attached to backing field:
    [field: NewPropertyOrField]
    public string Description { get; set; } = string.Empty;
}

Pokud AllowMultiple je argumentem true , pak výsledný atribut lze použít více než jednou pro jednu entitu, jak je znázorněno v následujícím příkladu:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
class MultiUse : Attribute { }

[MultiUse]
[MultiUse]
class Class1 { }

[MultiUse, MultiUse]
class Class2 { }

V tomto případě MultiUseAttribute lze použít opakované použití, protože AllowMultiple je nastavena na true . Oba formáty zobrazené pro použití více atributů jsou platné.

Pokud Inherited je false , pak atribut nedědí třídy odvozené z třídy s atributy. Například:

[AttributeUsage(AttributeTargets.Class, Inherited = false)]
class NonInheritedAttribute : Attribute { }

[NonInherited]
class BClass { }

class DClass : BClass { }

V tomto případě NonInheritedAttribute se nepoužije na DClass dědění.

Tato klíčová slova můžete také použít k určení, kde má být atribut použit. Například můžete použít field: specifikátor pro přidání atributu do pole pro zálohování s automaticky implementovanou vlastností. Případně můžete použít field: property: param: specifikátor nebo pro použití atributu na kterýkoli z prvků vygenerovaných z pozičního záznamu. Příklad naleznete v tématu poziční syntaxe pro definici vlastnosti.

Atribut AsyncMethodBuilder

Počínaje jazykem C# 7 přidáte System.Runtime.CompilerServices.AsyncMethodBuilderAttribute atribut na typ, který může být asynchronní návratový typ. Atribut určuje typ, který sestaví implementaci asynchronní metody při vrácení zadaného typu z asynchronní metody. AsyncMethodBuilderAtribut lze použít pro typ, který:

Konstruktor na AsyncMethodBuilder atribut určuje typ přidruženého tvůrce. Tvůrce musí implementovat následující dostupné členy:

  • Statická Create() metoda, která vrací typ Tvůrce.

  • Čitelná Task vlastnost, která vrací asynchronní návratový typ.

  • void SetException(Exception)Metoda, která nastavuje výjimku, pokud dojde k chybám úloh.

  • void SetResult()Metoda nebo void SetResult(T result) , která označuje úkol jako dokončený a volitelně nastavuje výsledek úkolu

  • StartMetoda s následujícím podpisem rozhraní API:

    void Start<TStateMachine>(ref TStateMachine stateMachine)
              where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine
    
  • AwaitOnCompletedMetoda s následujícím podpisem:

    public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
        where TAwaiter : System.Runtime.CompilerServices.INotifyCompletion
        where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine
    
  • AwaitUnsafeOnCompletedMetoda s následujícím podpisem:

          public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
              where TAwaiter : System.Runtime.CompilerServices.ICriticalNotifyCompletion
              where TStateMachine : System.Runtime.CompilerServices.IAsyncStateMachine
    

Informace o sestavách asynchronních metod si můžete přečíst v následujících sestavách, které poskytuje .NET:

V jazyce C# 10 a novějším AsyncMethodBuilder lze atribut použít pro asynchronní metodu pro přepsání tvůrce pro daný typ.

InterpolatedStringHandler a InterpolatedStringHandlerArguments atributy

Počínaje jazykem C# 10 použijete tyto atributy k určení toho, že typ je interpolovaná řetězcová obslužná rutina. Knihovna rozhraní .NET 6 již obsahuje ve System.Runtime.CompilerServices.DefaultInterpolatedStringHandler scénářích, kde jako argument pro parametr použijete interpolující řetězec string . Můžete mít další instance, u kterých chcete řídit, jak se zpracovávají interpolované řetězce. Můžete použít System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute pro typ, který implementuje vaši obslužnou rutinu. Použijete System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute parametry pro konstruktor daného typu.

Další informace o vytváření interpolované řetězcové obslužné rutiny najdete v části specifikace funkce C# 10 pro interpolovaná řetězcová vylepšení.

Atribut ModuleInitializer

Počínaje jazykem C# 9 ModuleInitializer atribut označuje metodu, kterou modul runtime volá při načtení sestavení. ModuleInitializer je alias pro ModuleInitializerAttribute .

ModuleInitializerAtribut lze použít pouze pro metodu, která:

  • Je statická.
  • Je bez parametrů.
  • Vrací objekt void.
  • Je přístupný z obsahujícího modulu, to znamená internal nebo public .
  • Není to obecná metoda.
  • Není obsažen v obecné třídě.
  • Není to místní funkce.

Atribut ModuleInitializer lze použít na více metod. V takovém případě je pořadí, ve kterém je modul runtime volá, deterministické, ale nezadá se.

Následující příklad ukazuje použití více inicializátorů modulů. Metody Init1 Init2 a se spustí před a každá přidá Main řetězec do Text vlastnosti . Při spuštění Main tedy vlastnost již obsahuje řetězce z obou Text inicializátorových metod.

using System;

internal class ModuleInitializerExampleMain
{
    public static void Main()
    {
        Console.WriteLine(ModuleInitializerExampleModule.Text);
        //output: Hello from Init1! Hello from Init2!
    }
}
using System.Runtime.CompilerServices;

internal class ModuleInitializerExampleModule
{
    public static string? Text { get; set; }

    [ModuleInitializer]
    public static void Init1()
    {
        Text += "Hello from Init1! ";
    }

    [ModuleInitializer]
    public static void Init2()
    {
        Text += "Hello from Init2! ";
    }
}

Generátory zdrojových kódů někdy potřebují vygenerovat inicializační kód. Inicializátory modulů poskytují standardní místo pro tento kód.

Atribut SkipLocalsInit

Počínaje jazykem C# 9 atribut brání kompilátoru v nastavení příznaku SkipLocalsInit .locals init při potvrzování metadat. Atribut je jedno použití atributu a lze použít na SkipLocalsInit metodu, vlastnost, třídu, struktury, rozhraní nebo modul, ale ne na sestavení. SkipLocalsInit je alias pro SkipLocalsInitAttribute .

Příznak způsobí, že modul CLR inicializuje všechny místní proměnné deklarované v .locals init metodě na výchozí hodnoty. Vzhledem k tomu, že kompilátor také zajišťuje, že nikdy nepoužívejte proměnnou před přiřazením nějaké hodnoty, .locals init obvykle není nezbytné. V některých scénářích, například při použití stackalloc k přidělení pole v zásobníku, ale navíc nulová inicializace může mít měřitelný dopad na výkon. V těchto případech můžete přidat SkipLocalsInit atribut . Pokud se použije přímo na metodu, atribut ovlivní tuto metodu a všechny její vnořené funkce, včetně výrazů lambda a místních funkcí. Pokud se použije na typ nebo modul, ovlivní to všechny metody vnořené uvnitř. Tento atribut nemá vliv na abstraktní metody, ale má vliv na kód vygenerovaný pro implementaci.

Tento atribut vyžaduje možnost kompilátoru AllowUnsafeBlocks. Tento požadavek signalizuje, že v některých případech může kód zobrazit nepřiřazenou paměť (například čtení z neinicializované paměti přidělené zásobníkem).

Následující příklad ukazuje účinek SkipLocalsInit atributu na metodu, která používá stackalloc . Metoda zobrazí vše, co bylo v paměti, když bylo přiděleno pole celých čísel.

[SkipLocalsInit]
static void ReadUninitializedMemory()
{
    Span<int> numbers = stackalloc int[120];
    for (int i = 0; i < 120; i++)
    {
        Console.WriteLine(numbers[i]);
    }
}
// output depends on initial contents of memory, for example:
//0
//0
//0
//168
//0
//-1271631451
//32767
//38
//0
//0
//0
//38
// Remaining rows omitted for brevity.

Pokud si chcete tento kód vyzkoušet sami, AllowUnsafeBlocks nastavte v souboru .csproj možnost kompilátoru:

<PropertyGroup>
  ...
  <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

Viz také