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:
- Jeśli musisz uzyskać dostęp do atrybutów w metadanych programu. Aby uzyskać więcej informacji, zobacz Pobieranie informacji przechowywanych w atrybutach.
- Do badania i instancjonowania typów w zestawie.
- Do tworzenia nowych typów w czasie wykonywania. Użyj klas w System.Reflection.Emit.
- W przypadku wykonywania opóźnionych powiązań uzyskiwanie dostępu do metod dla typów utworzonych w czasie wykonywania. Zobacz artykuł Dynamiczne ładowanie i używanie typów.
Powiązane sekcje
Aby uzyskać więcej informacji: