Odpowiedzi:
Metadane Dane o twoich obiektach / metodach / właściwościach.
Na przykład mogę zadeklarować atrybut o nazwie: DisplayOrder, dzięki czemu mogę łatwo kontrolować, w jakiej kolejności właściwości powinny pojawiać się w interfejsie użytkownika. Mógłbym następnie dołączyć go do klasy i napisać niektóre komponenty GUI, które wyodrębnią atrybuty i odpowiednio uporządkują elementy interfejsu.
public class DisplayWrapper
{
private UnderlyingClass underlyingObject;
public DisplayWrapper(UnderlyingClass u)
{
underlyingObject = u;
}
[DisplayOrder(1)]
public int SomeInt
{
get
{
return underlyingObject .SomeInt;
}
}
[DisplayOrder(2)]
public DateTime SomeDate
{
get
{
return underlyingObject .SomeDate;
}
}
}
W ten sposób upewniam się, że SomeInt jest zawsze wyświetlany przed SomeDate podczas pracy z moimi niestandardowymi komponentami GUI.
Jednak zobaczysz je najczęściej używane poza środowiskiem bezpośredniego kodowania. Na przykład projektant systemu Windows korzysta z nich w szerokim zakresie, dzięki czemu wie, jak postępować z niestandardowymi obiektami. Używanie BrowsableAttribute w taki sposób:
[Browsable(false)]
public SomeCustomType DontShowThisInTheDesigner
{
get{/*do something*/}
}
Informuje projektanta, aby nie podawał tego na przykład w dostępnych właściwościach w oknie Właściwości w czasie projektowania.
Państwo mogli również wykorzystać je do kodu generacji, operacje pre-kompilacji (takie jak post-ostre) operacji lub run-time, takich jak Reflection.Emit. Na przykład możesz napisać trochę kodu do profilowania, który będzie przezroczyście zawijał każde wywołanie twojego kodu i jego czas. Możesz „zrezygnować” z timingu za pomocą atrybutu umieszczanego na poszczególnych metodach.
public void SomeProfilingMethod(MethodInfo targetMethod, object target, params object[] args)
{
bool time = true;
foreach (Attribute a in target.GetCustomAttributes())
{
if (a.GetType() is NoTimingAttribute)
{
time = false;
break;
}
}
if (time)
{
StopWatch stopWatch = new StopWatch();
stopWatch.Start();
targetMethod.Invoke(target, args);
stopWatch.Stop();
HandleTimingOutput(targetMethod, stopWatch.Duration);
}
else
{
targetMethod.Invoke(target, args);
}
}
Deklarowanie ich jest łatwe, po prostu stwórz klasę, która dziedziczy po atrybucie.
public class DisplayOrderAttribute : Attribute
{
private int order;
public DisplayOrderAttribute(int order)
{
this.order = order;
}
public int Order
{
get { return order; }
}
}
I pamiętaj, że kiedy użyjesz atrybutu, możesz pominąć sufiks „atrybut”, kompilator doda to dla ciebie.
UWAGA: Atrybuty nic nie robią same - musi być jakiś inny kod, który ich używa. Czasami ten kod został napisany dla ciebie, ale czasem musisz go napisać sam. Na przykład kompilator C # dba o niektóre, a niektóre frameworki frameworków używają niektórych (np. NUnit szuka [TestFixture] w klasie i [Test] w metodzie testowej podczas ładowania zestawu).
Tworząc własny atrybut niestandardowy, pamiętaj, że w ogóle nie wpłynie to na zachowanie twojego kodu. Musisz napisać drugą część, która sprawdza atrybuty (poprzez odbicie) i działać na nich.
Wiele osób odpowiedziało, ale jak dotąd nikt o tym nie wspominał ...
Atrybuty są często używane z odbiciem. Odbicie jest już dość powolne.
Bardzo ważne jest oznaczenie niestandardowych atrybutów jako sealed
klas, aby poprawić ich wydajność.
Dobrym pomysłem jest również zastanowienie się, gdzie należałoby zastosować miejsce takiego atrybutu i przypisanie atrybutu (!), Aby wskazać to za pośrednictwem AttributeUsage
. Lista dostępnych zastosowań atrybutów może Cię zaskoczyć:
Fajnie jest też, że atrybut AttributeUsage jest częścią podpisu atrybutu AttributeUsage. Łał dla okrągłych zależności!
[AttributeUsageAttribute(AttributeTargets.Class, Inherited = true)]
public sealed class AttributeUsageAttribute : Attribute
Atrybuty są rodzajem metadanych do tagowania klas. Jest to często używane w WinForm, na przykład do ukrywania kontrolek na pasku narzędzi, ale można je zaimplementować we własnej aplikacji, aby umożliwić instancjom różnych klas zachowanie się w określony sposób.
Zacznij od utworzenia atrybutu:
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
public class SortOrderAttribute : Attribute
{
public int SortOrder { get; set; }
public SortOrderAttribute(int sortOrder)
{
this.SortOrder = sortOrder;
}
}
Wszystkie klasy atrybutów muszą mieć przyrostek „Atrybut”, aby były poprawne.
Po wykonaniu tej czynności utwórz klasę korzystającą z atrybutu.
[SortOrder(23)]
public class MyClass
{
public MyClass()
{
}
}
Teraz możesz sprawdzić określoną klasę ” SortOrderAttribute
(jeśli ma taką), wykonując następujące czynności:
public class MyInvestigatorClass
{
public void InvestigateTheAttribute()
{
// Get the type object for the class that is using
// the attribute.
Type type = typeof(MyClass);
// Get all custom attributes for the type.
object[] attributes = type.GetCustomAttributes(
typeof(SortOrderAttribute), true);
// Now let's make sure that we got at least one attribute.
if (attributes != null && attributes.Length > 0)
{
// Get the first attribute in the list of custom attributes
// that is of the type "SortOrderAttribute". This should only
// be one since we said "AllowMultiple=false".
SortOrderAttribute attribute =
attributes[0] as SortOrderAttribute;
// Now we can get the sort order for the class "MyClass".
int sortOrder = attribute.SortOrder;
}
}
}
Jeśli chcesz przeczytać więcej na ten temat, zawsze możesz sprawdzić MSDN, który ma całkiem niezły opis.
Mam nadzieję, że to ci pomogło!
Atrybut to klasa zawierająca trochę funkcjonalności, którą można zastosować do obiektów w kodzie. Aby je utworzyć, utwórz klasę dziedziczącą z System.Attribute.
Jeśli chodzi o to, do czego są dobre ... są prawie nieograniczone zastosowania.
Atrybuty są jak metadane stosowane do klas, metod lub zestawów.
Są dobre dla dowolnej liczby rzeczy (wizualizacja debuggera, oznaczanie rzeczy jako przestarzałe, oznaczanie rzeczy jako możliwe do serializacji, lista jest nieograniczona).
Tworzenie własnych jest łatwe jak ciasto. Zacznij tutaj:
http://msdn.microsoft.com/en-us/library/sw480ze8(VS.71).aspx
W projekcie, nad którym obecnie pracuję, jest zestaw obiektów interfejsu użytkownika o różnych smakach oraz edytor do składania tych obiektów w celu tworzenia stron do użycia w głównej aplikacji, trochę jak projektant formularzy w DevStudio. Te obiekty istnieją we własnym zestawie, a każdy obiekt jest klasą pochodną UserControl
i ma niestandardowy atrybut. Ten atrybut jest zdefiniowany w następujący sposób:
[AttributeUsage (AttributeTargets::Class)]
public ref class ControlDescriptionAttribute : Attribute
{
public:
ControlDescriptionAttribute (String ^name, String ^description) :
_name (name),
_description (description)
{
}
property String ^Name
{
String ^get () { return _name; }
}
property String ^Description
{
String ^get () { return _description; }
}
private:
String
^ _name,
^ _description;
};
i stosuję to do takiej klasy:
[ControlDescription ("Pie Chart", "Displays a pie chart")]
public ref class PieControl sealed : UserControl
{
// stuff
};
tak mówią poprzednie plakaty.
Aby użyć tego atrybutu, edytor zawiera Generic::List <Type>
typy kontrolek. Istnieje pole listy, z którego użytkownik może przeciągnąć i upuścić na stronę, aby utworzyć instancję formantu. Aby zapełnić pole listy, uzyskuję ControlDescriptionAttribute
kontrolę i wypełniam wpis na liście:
// done for each control type
array <Object ^>
// get all the custom attributes
^attributes = controltype->GetCustomAttributes (true);
Type
// this is the one we're interested in
^attributetype = ECMMainPageDisplay::ControlDescriptionAttribute::typeid;
// iterate over the custom attributes
for each (Object ^attribute in attributes)
{
if (attributetype->IsInstanceOfType (attribute))
{
ECMMainPageDisplay::ControlDescriptionAttribute
^description = safe_cast <ECMMainPageDisplay::ControlDescriptionAttribute ^> (attribute);
// get the name and description and create an entry in the list
ListViewItem
^item = gcnew ListViewItem (description->Name);
item->Tag = controltype->Name;
item->SubItems->Add (description->Description);
mcontrols->Items->Add (item);
break;
}
}
Uwaga: powyższe to C ++ / CLI, ale konwersja do C # nie jest trudna (tak, wiem, C ++ / CLI to obrzydliwość, ale z tym muszę pracować :-()
Możesz umieścić atrybuty na większości rzeczy i istnieje cały szereg predefiniowanych atrybutów. Wspomniany powyżej edytor szuka również niestandardowych atrybutów właściwości, które opisują właściwość i sposób jej edycji.
Gdy zrozumiesz cały pomysł, będziesz się zastanawiać, jak żyłeś bez nich.
Jak już wspomniano, atrybuty są stosunkowo łatwe do utworzenia. Drugą częścią pracy jest tworzenie kodu, który z niego korzysta. W większości przypadków będziesz używać refleksji w czasie wykonywania, aby zmieniać zachowanie w oparciu o obecność atrybutu lub jego właściwości. Istnieją również scenariusze, w których będziesz sprawdzał atrybuty skompilowanego kodu, aby przeprowadzić analizę statyczną. Na przykład parametry mogą być oznaczone jako niepuste, a narzędzie analityczne może wykorzystać to jako podpowiedź.
Wykorzystanie atrybutów i znajomość odpowiednich scenariuszy do ich użycia to większość pracy.
Atrybuty to przede wszystkim fragmenty danych, które chcesz dołączyć do swoich typów (klasy, metody, zdarzenia, wyliczenia itp.)
Chodzi o to, że w czasie wykonywania jakiś inny typ / framework / narzędzie będzie sprawdzał twoje typu o informacje w atrybucie i do niego.
Na przykład program Visual Studio może wyszukiwać atrybuty w formancie innej firmy, aby dowiedzieć się, które właściwości formantu powinny pojawić się w panelu Właściwości w czasie projektowania.
Atrybuty mogą być również używane w programowaniu aspektowym do wstrzykiwania / manipulowania obiektami w czasie wykonywania na podstawie atrybutów, które je dekorują i dodają sprawdzanie poprawności, rejestrowanie itp. Do obiektów bez wpływu na logikę biznesową obiektu.
Możesz użyć niestandardowych atrybutów jako prostego sposobu definiowania wartości znaczników w podklasach bez konieczności ciągłego pisania tego samego kodu dla każdej podklasy. Znalazłem ładny zwięzły przykład autorstwa Johna Watersa, w jaki sposób definiować i wykorzystywać niestandardowe atrybuty we własnym kodzie.
Jest tutorial na stronie http://msdn.microsoft.com/en-us/library/aa288454(VS.71).aspx
Aby rozpocząć tworzenie atrybutu, otwórz plik źródłowy C #, wpisz attribute
i naciśnij [TAB]. Rozwinie się do szablonu dla nowego atrybutu.