Einzelnen Beitrag anzeigen

Benutzerbild von sakura
sakura

Registriert seit: 10. Jun 2002
Ort: München
11.412 Beiträge
 
Delphi 11 Alexandria
 
#5

Re: Einführung in die .NET Framework Klassen Bibliothek

  Alt 11. Okt 2004, 14:51
Attribute und der System.Attribute Typ


Attribute werden genutzt, um Typen und Typen-Members (z.B. Felder, Eigenschaften, Methoden) zu "dekorieren". Attribute werden als Metadaten innerhalb einer .NET Framework Anwendung (oder Assembly) gesichert. Zur Laufzeit kann man Typen, Typen-Members und Instanzen auf das Vorkommen solcher Attribute hin überprüfen.

Die generelle Syntax für Delphi und C# ist im Grunde gleich und kommt direkt vor dem Symbol, auf welches das Attribut angewandt wird:
Code:
[AttributeTypeName(Parameter, Parameter)]
[b]public class [/b]Foo { ... }
Hinweis: Es ist definiert, dass Attributnamen immer auf das Wort Attribute enden (z.B.: DesignerAttribute, ComVisibleAttribute). Die meisten Compiler erlauben es einem den Teil "Attribute" wegzulassen.

Was kann man nun mit diesen Attributen anfangen? Die meisten Entwicklungsumgebungen bieten spezielle Design-Time Klassen, welche es einem ermöglichen eine Komponente/ein Control in der Oberfläche (zur Designzeit) zu modifizieren. Dazu dient (in .NET) zum Beispiel das DesignerAttribute:
Code:
      [DesignerAttribute("MyControlDesigner")]
      [b]public class [/b]MyControl : System.Windows.Forms.Control
      { … }
Wenn der WinForms Designer einen Designer für ein Control erstellt, stößt dieser auf das [i]DesignerAttribute[i] der Klasse und erstellt einen MyControllDesigner für diese.

Ein weiteres gutes Beispiel ist ComVisibleAttribute. Man kann .NET Assemblies dem COM Subsystem zur Verfügung stellen, indem man diese mit regasm.exe registriert. Jeder Typ, welcher mit ComVisibleAttribute markiert ist wird damit dem COM Subsystem zugänglich:
Code:
      [ComVisible(true)]
      [b]public interface [/b]MyInterface
      {

      }
Man kann sich jetzt die Frage stellen, ob man jetzt jeden Typ so markieren muss, der dem COM Subsystem zur Verfügung gestellt werden soll. Die Antwort ist: nein. Man kann dieses Attribut auch dem gesamten Assembly zur Verfügung stellen:
Code:
[assembly: ComVisible(true)]
Assembly-Level Attribute können auch für andere Dinge genutzt werden (z.B.: Version, Autor, Firmenname, etc.):
Code:
[assembly: AssemblyTitle("This is my cool assembly")]
[assembly: AssemblyDescription("It does neat stuff")]
[assembly: AssemblyCompany("Borland Software Corporation")]
[assembly: AssemblyVersion("1.0.3.5")]
Attribute abfragen

Um Attribute für einen Typen oder eine Instanz zu ermitteln kann man sich der Reflection und des TypeDescriptor bedienen:
Delphi-Quellcode:
var
  Attributes: AttributeCollection;
begin
  Attributes := TypeDescriptor.GetAttributes(Self);
Hinweis: Man kann eine Instanz (z.B: Self in Delphi oder this in C#) oder auch einen Sysmte.Type an TypeDescriptor.GetAttributes übergeben. Im Hintergrund wird immer auf den Typ zugegriffen, da Attribute Metadaten sind und diese im Typ, nicht in der Instanz, gesichert sind.

Nachdem man Zugriff auf die AttributeCollection erlangt hat, kann man diese recht einfach durchlaufen:
Delphi-Quellcode:
for AnAttribute in Attributes do
  begin
    TextBox1.Text := TextBox1.Text + AnAttribute.ToString + #13#10;
  end;
Hinweis: Hier wurde die neuere "Delphi 9" for-Schleifen-Syntax genutzt. In Delphi 8 muss man den Iterator manuell erstellen und durchlaufen.

Wenn man nur auf ein bestimmtes Attribute zugreifen möchte, so kann man das wie folgend tun:
Delphi-Quellcode:
var
  Attributes: AttributeCollection;
  DefaultEventAttr: DefaultEventAttribute;
begin
...
  DefaultEventAttr :=
      DefaultEventAttribute(Attributes[TypeOf(DefaultEventAttribute)]);
  if DefaultEventAttr <> nil then
    Text := 'Has a Default Event name of: ' + DefaultEventAttr.Name;
Man beachte, dass null zurückgeliefert wird, wenn der Typ keine Attribute besitzt.

Wenn man die Attribute eines bestimmten Mitgliedes (Type-Member) ermitteln möchte, muss man Reflection nutzen, um das Mitlgied zu finden. Anschließend kann man Attribute.GetCustomAttributes(..) nutzen, um auf die Attribute des Mitgliedes zuzugreifen:
Delphi-Quellcode:
[TMyCustomMethodAttriute]
procedure TMainForm.Button1_Click(sender: System.Object; e: System.EventArgs);
var
  MyType: System.Type;
  ClickMethod: MethodInfo;
  MethodAttrs: array of Attribute;
  MethodAttr: Attribute;
  I: Integer;
begin
  { Use reflection to get the Button1_Click member}
  MyType := GetType;
 
  ClickMethod := MyType.GetMethod('Button1_Click', BindingFlags.NonPublic or BindingFlags.Instance);
  MethodAttrs := Attribute.GetCustomAttributes(ClickMethod);
  TextBox1.Text := '--- Method Attributes --- '#13#10;
  for I := 0 to Length(MethodAttrs) - 1 do
  begin
    MethodAttr := MethodAttrs[I];
    TextBox1.Text := TextBox1.Text + MethodAttr.ToString + #13#10;
  end;
Wenn man Attribute.GetCustomAttributes(..) nutzt, kann man einen zweiten Parameter übergeben, um auch die Vorgängertypen zu untersuchen. In diesem Beispiel würde es nichts ändern, da diese Methode keine Vorgänger hat.

Eigene Attribute

Es ist recht einfach eigene Attribute zu erstellen. Man muss nur wenige Dinge beachten. Am wichtigsten ist, das jedes Attribute direkt oder indirekt von System.Attribute abgeleitet werden muss:
Delphi-Quellcode:
  { This can only be applied to methods }
  [AttributeUsage(AttributeTargets.Method)]
  TMyCustomMethodAttriute = class(Attribute)

  end;
Hinweis: Bachten Sie, dass das AttributeUsage Attribute dem neuen Attribute hinzugefügt wurde. Das teilt dem Compiler mit, dass dieses Attribute auch als solches genutzt werden darf.
Daniel W.