Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Atrybuty umożliwiają kojarzenie informacji z kodem w sposób deklaratywny. Mogą również udostępniać element wielokrotnego użytku, który można zastosować do różnych elementów docelowych. Rozważmy element ObsoleteAttribute. Można go stosować do klas, struktur, metod, konstruktorów i nie tylko. Deklaruje, że element jest przestarzały. Następnie odpowiedzialność za wyszukanie tego atrybutu spoczywa na kompilatorze języka C#, aby podjąć określoną akcję w odpowiedzi.
Z tego samouczka dowiesz się, jak dodawać atrybuty do kodu, jak tworzyć i używać własnych atrybutów oraz jak używać niektórych atrybutów wbudowanych w platformę .NET.
Wymagania wstępne
Aby uruchomić platformę .NET, musisz skonfigurować maszynę. Instrukcje instalacji można znaleźć na stronie Pliki do pobrania platformy .NET . Tę aplikację można uruchomić w systemach Windows, Ubuntu Linux, macOS lub w kontenerze platformy Docker. Musisz zainstalować ulubiony edytor kodu. Poniższe opisy używają programu Visual Studio Code, który jest edytorem międzyplatformowym typu open source. Można jednak użyć dowolnych narzędzi, które są dla ciebie wygodne.
Tworzenie aplikacji
Po zainstalowaniu wszystkich narzędzi utwórz nową aplikację konsolową platformy .NET. Aby użyć generatora wiersza poleceń, uruchom następującą komendę w ulubionej powłoce.
dotnet new console
To polecenie tworzy podstawowe pliki projektów .NET. Uruchom polecenie dotnet restore
, aby przywrócić zależności potrzebne do skompilowania tego projektu.
Nie musisz uruchamiać dotnet restore
, ponieważ jest ona uruchamiana niejawnie przez wszystkie polecenia, które wymagają przywrócenia, takie jak dotnet new
, dotnet build
, dotnet run
, dotnet test
, dotnet publish
i dotnet pack
. Aby wyłączyć niejawne przywracanie, użyj opcji --no-restore
.
Polecenie dotnet restore
jest nadal przydatne w niektórych scenariuszach, w których jawne przywracanie pakietów ma sens, takie jak w budowaniu ciągłej integracji w środowisku Azure DevOps Services lub w systemach kompilacji, które muszą jawnie kontrolować, kiedy następuje przywracanie pakietów.
Aby uzyskać informacje na temat zarządzania kanałami informacyjnymi NuGet, zobacz dokumentację dotnet restore
.
Aby wykonać program, użyj polecenia dotnet run
. Na konsoli powinien pojawić się napis "Hello, World".
Dodawanie atrybutów do kodu
W języku C# atrybuty to klasy dziedziczone z klasy bazowej Attribute
. Każda klasa, która dziedziczy z Attribute
, może służyć jako rodzaj "tagu" w innych częściach kodu. Na przykład istnieje atrybut o nazwie ObsoleteAttribute
. Ten atrybut sygnalizuje, że kod jest przestarzały i nie powinien już być używany. Ten atrybut należy umieścić na klasie, na przykład przy użyciu nawiasów kwadratowych.
[Obsolete]
public class MyClass
{
}
Chociaż klasa nazywa się ObsoleteAttribute
, konieczne jest użycie [Obsolete]
w kodzie. Większość kodu w języku C# jest zgodna z tą konwencją. Jeśli wybierzesz, możesz użyć pełnej nazwy [ObsoleteAttribute]
.
W przypadku oznaczania klasy przestarzałą warto podać pewne informacje, dlaczego są przestarzałe i/lub co zamiast tego należy użyć. Aby podać to wyjaśnienie, dołącz parametr ciągu do atrybutu Przestarzałe.
[Obsolete("ThisClass is obsolete. Use ThisClass2 instead.")]
public class ThisClass
{
}
Ciąg jest przekazywany jako argument do konstruktora ObsoleteAttribute
, tak jakby pisać var attr = new ObsoleteAttribute("some string")
.
Parametry konstruktora atrybutu są ograniczone do prostych typów/literałów: bool, int, double, string, Type, enums, etc
i tablic tych typów.
Nie można użyć wyrażenia ani zmiennej. Możesz swobodnie używać parametrów pozycyjnych lub nazwanych.
Tworzenie własnego atrybutu
Atrybut można utworzyć, definiując nową klasę dziedziczą po klasie bazowej Attribute
.
public class MySpecialAttribute : Attribute
{
}
W poprzednim kodzie można użyć [MySpecial]
(lub [MySpecialAttribute]
) jako atrybutu w innym miejscu w bazie kodu.
[MySpecial]
public class SomeOtherClass
{
}
Atrybuty w bibliotece klas bazowych platformy .NET, takie jak ObsoleteAttribute
wyzwalają pewne zachowania w kompilatorze. Jednak każdy utworzony atrybut działa tylko jako metadane i nie powoduje wykonania żadnego kodu w klasie atrybutów. To ty musisz wykonywać działania na tych metadanych w innym miejscu w kodzie.
Jest tu pułapka, na którą trzeba uważać. Jak wspomniano wcześniej, tylko niektóre typy mogą być przekazywane jako argumenty podczas używania atrybutów. Jednak podczas tworzenia typu atrybutu kompilator języka C# nie powstrzymuje tworzenia tych parametrów. W poniższym przykładzie utworzono atrybut z konstruktorem, który kompiluje się poprawnie.
public class GotchaAttribute : Attribute
{
public GotchaAttribute(Foo myClass, string str)
{
}
}
Nie można jednak użyć tego konstruktora ze składnią atrybutów.
[Gotcha(new Foo(), "test")] // does not compile
public class AttributeFail
{
}
Powyższy kod powoduje błąd kompilatora, taki jak Attribute constructor parameter 'myClass' has type 'Foo', which is not a valid attribute parameter type
Jak ograniczyć użycie atrybutów
Atrybuty mogą być używane z następującymi celami. Powyższe przykłady pokazują je na zajęciach, ale mogą być także używane w:
- Zgromadzenie
- Klasa
- Konstruktor
- Delegować
- Typ wyliczeniowy
- Zdarzenie
- (No changes needed)
- Parametr ogólny
- Interfejs
- Metoda
- Moduł
- Parametr
- Majątek
- ReturnValue
- Struktur
Podczas tworzenia klasy atrybutów domyślnie język C# umożliwia używanie tego atrybutu na dowolnym z możliwych obiektów docelowych atrybutów. Jeśli chcesz ograniczyć atrybut do określonych obiektów docelowych, możesz to zrobić przy użyciu klasy atrybutów AttributeUsageAttribute
. To prawda, atrybut na atrybucie!
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class MyAttributeForClassAndStructOnly : Attribute
{
}
Jeśli próbujesz umieścić powyższy atrybut na czymś, co nie jest klasą lub strukturą, zostanie wyświetlony błąd kompilatora, taki jak Attribute 'MyAttributeForClassAndStructOnly' is not valid on this declaration type. It is only valid on 'class, struct' declarations
public class Foo
{
// if the below attribute was uncommented, it would cause a compiler error
// [MyAttributeForClassAndStructOnly]
public Foo()
{ }
}
Jak używać atrybutów dołączonych do elementu kodu
Atrybuty działają jako metadane. Bez jakiejś siły zewnętrznej, nie robią nic.
Aby znaleźć atrybuty i działać na ich podstawie, potrzebna jest refleksja. Odbicie umożliwia pisanie kodu w języku C#, który analizuje inny kod. Na przykład można użyć odbicia, aby uzyskać informacje o klasie (dodaj using System.Reflection;
na czele kodu):
TypeInfo typeInfo = typeof(MyClass).GetTypeInfo();
Console.WriteLine("The assembly qualified name of MyClass is " + typeInfo.AssemblyQualifiedName);
To drukuje coś takiego jak: The assembly qualified name of MyClass is ConsoleApplication.MyClass, attributes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Po utworzeniu TypeInfo
obiektu (lub MemberInfo
obiektu , FieldInfo
lub innego obiektu) możesz użyć GetCustomAttributes
metody . Ta metoda zwraca kolekcję Attribute
obiektów. Można również użyć GetCustomAttribute
i określić typ atrybutu.
Oto przykład użycia GetCustomAttributes
na instancji MemberInfo
dla MyClass
(które, jak widzieliśmy wcześniej, ma atrybut [Obsolete]
na sobie).
var attrs = typeInfo.GetCustomAttributes();
foreach(var attr in attrs)
Console.WriteLine("Attribute on MyClass: " + attr.GetType().Name);
To drukuje do konsoli: Attribute on MyClass: ObsoleteAttribute
. Spróbuj dodać inne atrybuty do MyClass
elementu .
Należy pamiętać, że te Attribute
obiekty są tworzone z opóźnieniem. Oznacza to, że nie będą instancjonowane, dopóki nie zostanie użyta funkcja GetCustomAttribute
lub GetCustomAttributes
. Są one również tworzone za każdym razem. Wywołanie GetCustomAttributes
dwukrotnie z rzędu zwraca dwa różne wystąpienia ObsoleteAttribute
.
Typowe atrybuty w środowisku uruchomieniowym
Atrybuty są używane przez wiele narzędzi i struktur. NUnit używa atrybutów takich jak [Test]
i [TestFixture]
, które są używane przez moduł uruchamiający testy NUnit. ASP.NET MVC używa atrybutów, takich jak [Authorize]
i udostępnia strukturę filtru akcji do wykonywania problemów krzyżowych w akcjach MVC.
PostSharp używa składni atrybutów, aby umożliwić programowanie zorientowane na aspekty w języku C#.
Oto kilka godnych uwagi atrybutów wbudowanych w biblioteki klas bazowych platformy .NET Core:
-
[Obsolete]
. Ten został użyty w powyższych przykładach i znajduje się wSystem
przestrzeni nazw. Warto podać dokumentację deklaratywną dotyczącą zmieniającej się bazy kodu. Komunikat można podać w postaci ciągu, a inny parametr logiczny może służyć do eskalacji z ostrzeżenia kompilatora do błędu kompilatora. -
[Conditional]
. Ten atrybut znajduje się wSystem.Diagnostics
przestrzeni nazw. Ten atrybut można zastosować do metod (lub klas atrybutów). Należy przekazać ciąg do konstruktora. Jeśli ten ciąg nie jest zgodny z dyrektywą#define
, kompilator języka C# usuwa wszystkie wywołania tej metody (ale nie samej metody). Zazwyczaj ta technika jest używana do debugowania (diagnostyki). -
[CallerMemberName]
. Ten atrybut może być używany w parametrach i znajduje się wSystem.Runtime.CompilerServices
przestrzeni nazw.CallerMemberName
jest atrybutem używanym do wstrzykiwania nazwy metody wywołującej inną metodę. Jest to sposób na wyeliminowanie "ciągów magicznych" podczas implementowania funkcji INotifyPropertyChanged w różnych strukturach interfejsu użytkownika. Przykład:
public class MyUIClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public void RaisePropertyChanged([CallerMemberName] string propertyName = default!)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string? _name;
public string? Name
{
get { return _name;}
set
{
if (value != _name)
{
_name = value;
RaisePropertyChanged(); // notice that "Name" is not needed here explicitly
}
}
}
}
W powyższym kodzie nie trzeba mieć dosłownego ciągu znaków "Name"
. Użycie CallerMemberName
zapobiega błędom związanym z literówkami, a także umożliwia płynniejszą refaktoryzację i zmianę nazwy. Atrybuty zapewniają deklaratywną siłę w języku C#, ale są formą metadanych kodu i nie działają samodzielnie.