Udostępnij za pośrednictwem


Atrybuty

Atrybuty zapewniają zaawansowany sposób kojarzenia metadanych lub informacji deklaratywnych z kodem (zestawy, typy, metody, właściwości itd.). Po skojarzeniu atrybutu z jednostką programu można wykonać zapytanie dotyczące atrybutu w czasie wykonywania przy użyciu techniki o nazwie odbicie.

Atrybuty mają następujące właściwości:

  • Atrybuty dodają metadane do programu. Metadata to informacje o typach zdefiniowanych w programie. Wszystkie zestawy platformy .NET zawierają określony zestaw metadanych, który opisuje typy i składowe typu zdefiniowane w zestawie. Możesz dodać atrybuty niestandardowe, aby określić inne wymagane informacje.
  • Atrybuty można stosować do całych zestawów, modułów lub mniejszych elementów programu, takich jak klasy i właściwości.
  • Atrybuty mogą akceptować argumenty w taki sam sposób jak metody i właściwości.
  • Atrybuty umożliwiają programowi badanie własnych metadanych lub metadanych w innych programach przy użyciu odbicia.

Praca z refleksją

API refleksji udostępniane przez Type opisują zestawy, moduły i typy. Można użyć odbicia, aby dynamicznie utworzyć wystąpienie typu, powiązać typ z istniejącym obiektem lub pobrać typ z istniejącego obiektu i wywołać jego metody lub uzyskać dostęp do jego pól i właściwości. Gdy używasz atrybutów w kodzie, odbicie umożliwia dostęp do nich. Aby uzyskać więcej informacji, zobacz Atrybuty.

Oto prosty przykład odbicia za pomocą metody GetType(). Wszystkie typy z klasy bazowej Object dziedziczą tę metodę, która jest używana do uzyskiwania typu zmiennej:

Uwaga

Upewnij się, że dodano instrukcje using System; i using System.Reflection; w górnej części pliku kodu C# (.cs).

// Using GetType to obtain type information:
int i = 42;
Type type = i.GetType();
Console.WriteLine(type);

Dane wyjściowe zawierają typ:

System.Int32

W poniższym przykładzie użyto reflection w celu uzyskania pełnej nazwy załadowanego zestawu.

// Using Reflection to get information of an Assembly:
Assembly info = typeof(int).Assembly;
Console.WriteLine(info);

Dane wyjściowe są podobne do poniższego przykładu:

System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e

Różnice słów kluczowych dla IL

Słowa kluczowe języka C# protected i internal nie mają znaczenia w języku pośrednim (IL) i nie są używane w interfejsach API odbicia. Odpowiednie terminy w IL to Rodzina i Zgromadzenie. Poniżej przedstawiono kilka sposobów używania następujących terminów:

  • Aby zidentyfikować metodę internal przy użyciu odbicia, użyj właściwości IsAssembly.
  • Aby zidentyfikować metodę protected internal, użyj IsFamilyOrAssembly.

Praca z atrybutami

Atrybuty można umieścić na prawie każdej deklaracji, choć określony atrybut może ograniczyć typy deklaracji, na których jest prawidłowy. W języku C#należy określić atrybut, umieszczając nazwę atrybutu ujętego w nawiasy kwadratowe ([]) powyżej deklaracji jednostki, do której ma zastosowanie.

W tym przykładzie użyjesz atrybutu SerializableAttribute, aby zastosować konkretną charakterystykę do klasy:

[Serializable]
public class SampleClass
{
    // Objects of this type can be serialized.
}

Metodę można zadeklarować za pomocą atrybutu DllImportAttribute:

[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static void SampleMethod();

Można umieścić wiele atrybutów w deklaracji:

void MethodA([In][Out] ref double x) { }
void MethodB([Out][In] ref double x) { }
void MethodC([In, Out] ref double x) { }

Niektóre atrybuty można określić więcej niż raz dla danej jednostki. W poniższym przykładzie pokazano wielokrotne użycie atrybutu ConditionalAttribute.

[Conditional("DEBUG"), Conditional("TEST1")]
void TraceMethod()
{
    // ...
}

Uwaga

Zgodnie z konwencją wszystkie nazwy atrybutów kończą się sufiksem "Atrybut", aby odróżnić je od innych typów w bibliotekach platformy .NET. Nie trzeba jednak określać sufiksu atrybutu podczas używania atrybutów w kodzie. Na przykład deklaracja [DllImport] jest równoważna deklaracji [DllImportAttribute], ale DllImportAttribute jest rzeczywistą nazwą klasy w bibliotece klas platformy .NET.

Parametry atrybutów

Wiele atrybutów ma parametry, które mogą być pozycyjne, bezimiennelub nazwane. W poniższej tabeli opisano sposób pracy z nazwanymi i pozycyjnymi atrybutami:

parametry pozycyjne

Parametry konstruktora atrybutu:

nazwane parametry

Właściwości lub pola atrybutu:

  • Musi określić, nie można pominąć
  • Najpierw zawsze określaj
  • Określ w pewnej kolejności
  • Zawsze opcjonalny, pomiń, jeśli fałszywy
  • Określ po parametrach pozycyjnych
  • Określ w dowolnej kolejności

Na przykład poniższy kod przedstawia trzy równoważne atrybuty DllImport:

[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]

Pierwszy parametr, nazwa biblioteki DLL, jest pozycyjny i zawsze pojawia się jako pierwszy. Inne wystąpienia są nazwane parametrami. W tym scenariuszu oba nazwane parametry domyślnie mają wartość false, aby można je było pominąć. Zapoznaj się z dokumentacją poszczególnych atrybutów, aby uzyskać informacje na temat domyślnych wartości parametrów. Aby uzyskać więcej informacji na temat dozwolonych typów parametrów, zobacz sekcję Attributes w specyfikacji języka C#.

Cele atrybutów

docelowym atrybutu jest jednostka, do której ten atrybut się odnosi. Na przykład atrybut może być stosowany do klasy, metody lub zestawu. Domyślnie atrybut ma zastosowanie do elementu, który następuje po nim. Można jednak jawnie zidentyfikować element do skojarzenia, na przykład metodę, parametr lub wartość zwracaną.

Aby jawnie zidentyfikować element docelowy atrybutu, użyj następującej składni:

[target : attribute-list]

W poniższej tabeli przedstawiono listę możliwych wartości target.

Wartość docelowa Dotyczy
assembly Cały montaż
module Bieżący moduł montażu
field Pole w klasie lub w strukturze
event Zdarzenie
method Metoda lub get i set metody dostępu do właściwości
param Parametry metody lub parametry akcesora właściwości set
property Własność
return Zwracana wartość metody, indeksatora właściwości lub get akcesora właściwości
type Struktura, klasa, interfejs, wyliczenie lub delegat

Można określić wartość docelową field, aby zastosować atrybut do pomocniczego pola utworzonego dla automatycznie zaimplementowanej właściwości .

W poniższym przykładzie pokazano, jak zastosować atrybuty do zestawów i modułów. Aby uzyskać więcej informacji, zobacz Common attributes (C#).

using System;
using System.Reflection;
[assembly: AssemblyTitleAttribute("Production assembly 4")]
[module: CLSCompliant(true)]

W poniższym przykładzie pokazano, jak zastosować atrybuty do metod, parametrów metody i zwracanych wartości metody w języku C#.

// default: applies to method
[ValidatedContract]
int Method1() { return 0; }

// applies to method
[method: ValidatedContract]
int Method2() { return 0; }

// applies to parameter
int Method3([ValidatedContract] string contract) { return 0; }

// applies to return value
[return: ValidatedContract]
int Method4() { return 0; }

Uwaga

Niezależnie od obiektów docelowych, dla których atrybut ValidatedContract jest zdefiniowany jako prawidłowy, należy określić obiekt docelowy return, nawet jeśli atrybut ValidatedContract jest zdefiniowany w celu zastosowania tylko do zwracanych wartości. Innymi słowy, kompilator nie używa informacji AttributeUsage do rozpoznawania niejednoznacznych obiektów docelowych atrybutów. Aby uzyskać więcej informacji, zobacz AttributeUsage.

Przejrzyj sposoby używania atrybutów

Oto kilka typowych sposobów używania atrybutów w kodzie:

  • Oznacz metody kontrolera, które odpowiadają na komunikaty POST przy użyciu atrybutu HttpPost. Aby uzyskać więcej informacji, zobacz klasę HttpPostAttribute.
  • Opisz, jak zarządzać parametrami metody podczas współpracy z kodem natywnym. Aby uzyskać więcej informacji, zobacz klasę MarshalAsAttribute.
  • Opis właściwości modelu obiektów składników (COM) dla klas, metod i interfejsów.
  • Wywołaj kod niezarządzany przy użyciu klasy DllImportAttribute.
  • Opisz zestaw pod względem tytułu, wersji, opisu lub znaku towarowego.
  • Opisz, którzy członkowie klasy powinni być zserializowani w celu zapewnienia trwałości.
  • Opis sposobu mapowania między elementami członkowskimi klasy i węzłami XML na potrzeby serializacji XML.
  • Opisz wymagania dotyczące zabezpieczeń metod.
  • Określ właściwości używane do wymuszania zabezpieczeń.
  • Optymalizacja sterowania za pomocą kompilatora just in time (JIT), dzięki czemu kod pozostaje łatwy do debugowania.
  • Uzyskaj informacje o obiekcie wywołującym metodę.

Przeglądanie scenariuszy refleksji

Refleksja jest przydatna w następujących scenariuszach: