Archiv

Archiv für Juni, 2011

Vererbung von Properties entfernt die Attribute

Für eine Erweiterung von meinem Quellcode hatte ich geplant, ein paar Properties mit Attributen zu versehen. Dabei sollten die Properties virtual sein. Die Abfrage der Attribute sollte dann mittels GetCustomAttributes geschehen. Leider hat das gar nicht funktioniert, was auch schon andere .NET-Programmierer feststellen mussten. Darum habe ich die Problemstellung extrahiert:

Zum Prüfen der Attribute wurde folgende Funktion verwendet:

static void CheckAttribute(MemberInfo memberInfo)
{
    var attributes = memberInfo.GetCustomAttributes(true);
    if (attributes.Length == 0) return;
 
    foreach (object attribute in attributes)
        Console.WriteLine("The type of the attribute in {1} is {0}.", 
            attribute, memberInfo.Name);
}

Weiterhin wurden zwei Klassen geschrieben, wo einmal eine abgeleitete Methode und eine abgeleitete Propertie mit Attributen versehen wurde:

public abstract class BaseClass
{
    [TestAttribute]
    public virtual String TestProperty { get; set; }
 
    [TestAttribute]
    public virtual void TestMethod() { return; }
}
public class DerivedClass : BaseClass
{
    public override string TestProperty { get; set; }
    public override void TestMethod() { base.TestMethod(); }
}
 
public class TestAttribute : Attribute
{
}

Zu guter Letzt wurde das ganze überprüft:

Console.WriteLine("BaseClass:");
CheckAttribute(typeof(BaseClass).GetProperty("TestProperty"));
CheckAttribute(typeof(BaseClass).GetMethod("TestMethod"));
 
Console.WriteLine("DerivedClass:");
CheckAttribute(typeof(DerivedClass).GetProperty("TestProperty"));
CheckAttribute(typeof(DerivedClass).GetMethod("TestMethod"));

Das Ergebnis fiel überraschend aus:

BaseClass:
The type of the attribute in TestProperty is TestAttrib.TestAttribute.
The type of the attribute in TestMethod is TestAttrib.TestAttribute.
DerivedClass:
The type of the attribute in TestMethod is TestAttrib.TestAttribute.

Wähernd die Methode TestMethod in beiden Klassen als mit dem Attribut ausgezeichnet, erkannt wurde, war dies bei der Eigenschaft TestProperty nicht der Fall. Um die Ursache zu finden, war ein Blick in die IL notwendig. Hier die Umsetzung der BaseClass, welche das Attribute in beiden Fällen korrekt definiert.

.method public hidebysig newslot virtual instance void TestMethod() cil managed
{
    .custom instance void TestAttrib.TestAttribute::.ctor()
}
 
.property instance string TestProperty
{
    .get instance string TestAttrib.BaseClass::get_TestProperty()
    .set instance void TestAttrib.BaseClass::set_TestProperty(string)
    .custom instance void TestAttrib.TestAttribute::.ctor()
}

Die Ableitung war aber überaschend umgesetzt. Während die Methode offensichtlich überschrieben wurde, wurde die Propertie quasi neu angelegt, aber ohne dem zugewiesenen Attribut.

.method public hidebysig virtual instance void TestMethod() cil managed
{
}
 
.property instance string TestProperty
{
    .get instance string TestAttrib.DerivedClass::get_TestProperty()
    .set instance void TestAttrib.DerivedClass::set_TestProperty(string)
}

Damit war das Ergebnis der Untersuchung: GetCustomAttributes hat definitionsgemäß auch die Ableitungen untersucht. Jedoch verlieren sich die Attribute beim Überschreiben von Properties. Eine Erklärung dafür habe ich bis jetzt nicht gefunden, ich konnte den Effekt aber in .NET 2.0 – 4.0 nachstellen.