Jakie są atrybuty w .NET?

Odpowiedzi:

146

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.

Quibblesome
źródło
32
Dla tego, co jest warte, jest to lista wszystkich (wbudowanych) atrybutów .NET: msdn.microsoft.com/en-us/library/aa311259(VS.71).aspx
wprl
1
Jak użyjesz swojego „SomeProfilingMethod” jako atrybutu?
RayLoveless,
@RayLoveless nie jest to atrybut, SomeProfilingMethod to kod instrumentacji, który szuka atrybutów profilowania. Konkretnie w przykładzie podałem, że szukałem atrybutu „opt-out” (NoTimingAttribute) w przeciwieństwie do atrybutu „opt-in”. Chodzi o to, że wszystko razy razy.
Quibblesome
@Quibblesome czy możesz dodać coś takiego: „Atrybuty nic nie robią same - muszą być pewne inny kod, aby z nich korzystać (kompilator dba o parę, różne frameworki używają trochę). Samo tworzenie atrybutu nie wpłynie na zachowanie kodu - musisz napisać drugą część, która sprawdza atrybuty (poprzez refleksję) i działa na nich ”. (lub mogę to zrobić, jeśli wszystko jest w porządku). Wiele osób oczekuje, że atrybuty będą działać magicznie i żadna z odpowiedzi tutaj tego nie wyjaśnia. (lub po prostu link do stackoverflow.com/questions/4879521/…, który to obejmuje)
Alexei Levenkov
tylko jeśli przestaniesz używać Bing. Nie j / k Używam DuckDuckGo jako mojej podstawowej, która głównie używa Bing iirc. :)
Quibblesome
36

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 sealedklas, 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ć:

  • montaż
  • Moduł
  • Klasa
  • Struct
  • Enum
  • Konstruktor
  • metoda
  • własność
  • Pole
  • Zdarzenie
  • Berło
  • Parametr
  • Delegat
  • ReturnValue
  • GenericParameter
  • Wszystko

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
Drew Noakes
źródło
13

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!

Patrik Svensson
źródło
5

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.

http://www.codeproject.com/KB/cs/dotnetattributes.aspx

Smerf
źródło
1
„funkcjonalność” jest tutaj niewłaściwym słowem; są to metadane, a nie funkcjonalność
Marc Gravell
5

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

Stu
źródło
5

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ą UserControli 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ę ControlDescriptionAttributekontrolę 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.

Skizz
źródło
4

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.

Denis Phillips
źródło
3

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.

urini
źródło
2

Aby rozpocząć tworzenie atrybutu, otwórz plik źródłowy C #, wpisz attributei naciśnij [TAB]. Rozwinie się do szablonu dla nowego atrybutu.

Jay Bazuzi
źródło
6
Jak odpowiada na pytanie? powinien to być komentarz, a nie odpowiedź.
gdoron wspiera Monikę
1

Atrybuty są również powszechnie używane w programowaniu zorientowanym na aspekty. Przykład tego znajduje się w projekcie PostSharp .

Josh G.
źródło