Udostępnij za pośrednictwem


Atrybuty

Atrybuty zapewniają zaawansowaną metodę kojarzenia metadanych lub informacji deklaratywnych z kodem (zestawy, typy, metody, właściwości itd.). Gdy atrybut jest skojarzony z jednostką programu, można uzyskać dostęp do atrybutu w czasie wykonywania, używając 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ć wszelkie dodatkowe informacje, które są wymagane.
  • Można zastosować co najmniej jeden atrybut 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.
  • Twój program może zbadać własne metadane lub metadane w innych programach przy użyciu refleksji.

Reflection udostępnia obiekty (typu Type), które 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. Jeśli 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 przy użyciu metody GetType() — dziedziczonej przez wszystkie typy z klasy bazowej Object — w celu uzyskania typu zmiennej:

Uwaga

Upewnij się, że w górnej części pliku .cs dodano using System; i using System.Reflection;.

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

Dane wyjściowe to: 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);

Wynik jest podobny do: System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e.

Notatka

Słowa kluczowe języka C# protected i internal nie mają znaczenia w języku pośrednim (IL) i nie są używane w API refleksji. Odpowiednie terminy w IL to Rodzina i Zgromadzenie. Aby zidentyfikować metodę internal przy użyciu odbicia, użyj właściwości IsAssembly. Aby zidentyfikować metodę protected internal, użyj IsFamilyOrAssembly.

Używanie atrybutów

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 atrybut SerializableAttribute służy do stosowania konkretnej charakterystyki do klasy:

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

Metoda z atrybutem DllImportAttribute jest zadeklarowana jak w poniższym przykładzie:

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

Więcej niż jeden atrybut można umieścić w deklaracji, jak pokazano w poniższym przykładzie:

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. Przykładem takiego atrybutu wielokrotnego zastosowania jest ConditionalAttribute:

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

Notatka

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

Parametry atrybutu

Wiele atrybutów ma parametry, które mogą być pozycyjne, bez nazwy lub nazwane. Wszystkie parametry pozycyjne muszą być określone w określonej kolejności i nie można ich pominąć. Nazwane parametry są opcjonalne i można je określić w dowolnej kolejności. Parametry pozycyjne są określane jako pierwsze. Na przykład te trzy atrybuty są równoważne:

[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 są nazwane. W tym przypadku oba nazwane parametry są domyślnie wartością false, więc można je pominąć. Parametry pozycyjne odpowiadają parametrom konstruktora atrybutu. Parametry nazwane lub opcjonalne odpowiadają właściwościom lub polam atrybutu. 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, określonej metody lub całego zestawu. Domyślnie atrybut ma zastosowanie do elementu, który następuje po nim. Można jednak również jawnie zidentyfikować, czy atrybut jest stosowany do metody, czy do parametru, czy do jego wartości zwracanej.

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

[target : attribute-list]

Lista możliwych wartości target jest wyświetlana w poniższej tabeli.

Wartość docelowa Dotyczy
assembly Cały zestaw
module Bieżący moduł zestawu
field Pole w klasie lub w strukturze
event Zdarzenie
method Metody 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

Należy określić wartość docelową field, aby zastosować atrybut do pola pomocniczego 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; }

Notatka

Niezależnie od celów, na których zdefiniowano ValidatedContract jako prawidłowe, należy określić cel return, nawet jeśli ValidatedContract zostały zdefiniowane w celu zastosowania tylko do zwracanych wartości. Innymi słowy, kompilator nie będzie używać informacji AttributeUsage, aby rozwiązać niejednoznaczne cele atrybutów. Aby uzyskać więcej informacji, zobacz AttributeUsage.

Typowe zastosowania atrybutów

Poniższa lista zawiera kilka typowych zastosowań atrybutów w kodzie:

  • Oznaczanie metod przy użyciu atrybutu WebMethod w usługach sieci Web, aby wskazać, że metoda powinna być wywoływana za pośrednictwem protokołu SOAP. Aby uzyskać więcej informacji, zobacz WebMethodAttribute.
  • Opis sposobu zarządzania parametrami metody podczas współdziałania z kodem natywnym. Aby uzyskać więcej informacji, zobacz MarshalAsAttribute.
  • Opis właściwości modelu COM dla klas, metod i interfejsów.
  • Wywoływanie niezarządzanych kodu przy użyciu klasy DllImportAttribute.
  • Opisywanie zestawu pod względem tytułu, wersji, opisu lub znaku towarowego.
  • Opisanie, które elementy członkowskie klasy mają być serializowane w celu zapewnienia trwałości.
  • Opis sposobu mapowania między elementami członkowskimi klasy i węzłami XML na potrzeby serializacji XML.
  • Opis wymagań dotyczących zabezpieczeń metod.
  • Określanie właściwości używanych do wymuszania zabezpieczeń.
  • Kontrolowanie optymalizacji przez kompilator just in time (JIT), dzięki czemu kod pozostaje łatwy do debugowania.
  • Uzyskiwanie informacji o wywołującym metodę.

Przegląd refleksji

Refleksja jest przydatna w następujących sytuacjach:

Aby uzyskać więcej informacji: