none
Aus der MSDN-Hotline: Type.GetProperties Reihenfolge RRS feed

  • Allgemeine Diskussion

  • Hallo zusammen,
    heute wurde uns bei der MSDN-Entwickler-Hotline unter anderem folgende Frage gestellt:

    In der Dokumentation der Methode Type.GetProperties unter [1] heißt es:

    Die GetProperties-Methode gibt Eigenschaften nicht in einer bestimmten Reihenfolge zurück, d. h. nicht in alphabetischer Reihenfolge oder in der Reihenfolge der Deklaration. Der Code darf daher nicht von der Reihenfolge der zurückgegebenen Eigenschaften abhängen, da diese variieren kann.

    Wie kann ich nun die Reihenfolge der Eigenschaften herausfinden, in der sie im Code gestanden haben?

    Unsere Antwort bzw. unser Lösungsvorschlag darauf war:

    Nachträglich gibt es keine Möglichkeit, garantiert die Reihenfolge herauszufinden, in der die Eigenschaften im Code standen - gerade bei Partial Classes führt dies zu logischen Problemen, da der Begriff der Reihenfolge dann nicht mehr wohldefiniert ist.

    Zwar gibt die GetProperties-Methode die Eigenschaften tatsächlich in genau der selben Reihenfolge aus, in der sie im Code standen (so lange keine Partial Classes über mehrere Dateien verwendet werden), dieses Verhalten kann sich aber in Zukunft verändern. Von daher muss der Code mit Meta-Informationen versehen werden, um die Reihenfolge auch zur Laufzeit zu erhalten.

    So kann ein Order-Attribut implementiert werden, welches zu einer Eigenschaft einen numerischen Wert entgegen nimmt, der beim Auslesen als Schlüssel zum Sortieren verwendet wird. Um die Anwendung dieses Attributs etwas zu erleichtern, kann als Standart-Wert die Zeilennummer verwendet werden, indem das Attribut CallerLineNumber dem Parameter vorangestellt wird. Damit es bei Partial Classes, die evtl. den gleichen Codeumfang erreichen können, nicht zu Kollisionen der Zeilennummern kommen kann, sollte ein zweiter Sortier-Schlüssel mit dem Namen der Datei verwendet werden. Allerdings sollte bei Verwendung des CallerFilePath-Attributs darauf geachtet werden, dass im Kompilat dann der volle Dateiname der Klasse hinterlegt ist (da Attribute erst zur Laufzeit instanziiert werden, hiflt es auch nicht, im Konstruktor den Dateinamen auf eine andere ordnungserhaltende Struktur abzubilden).

    Der Code könnte dann wie folgt aussehen:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Text;
    using System.Threading.Tasks;
    using System.Reflection;
    
    namespace ConsoleApplicationAttributeOrder
    {
        [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)]
        public sealed class OrderAttribute : Attribute, IComparable<OrderAttribute>
        {
            public OrderAttribute([CallerFilePath] string sortKey1 = "", [CallerLineNumber]int sortKey2 = 0)
            {
                SortKey1 = sortKey1;
                SortKey2 = sortKey2;
            }
    
            public string SortKey1 { get; private set; }
    
            public int SortKey2 { get; private set; }
    
            public int CompareTo(OrderAttribute other)
            {
                var c1 = SortKey1.CompareTo(other.SortKey1);
                var c2 = SortKey2.CompareTo(other.SortKey2);
    
                return (c1 != 0) ? c1 : c2;
            }
        }
    
        partial class MyClass
        {
            [Order]
            public string Prop1 { get; set; }
    
            [Order]
            public string Prop2 { get; set; }
    
            [Order]
            public string Prop3 { get; set; }
        }
    
        partial class MyClass
        {
            [Order]
            public string Prop4 { get; set; }
    
            [Order]
            public string Prop5 { get; set; }
    
            [Order]
            public string Prop6 { get; set; }
        }
    
    
        class Program
        {
            static void Main(string[] args)
            {
                //Durch die Sortierung ist die korrekte Reihenfolge nun garantiert.
                foreach (var p in typeof(MyClass).GetProperties().OrderBy(p => p.GetCustomAttribute<OrderAttribute>()))
                {
                    Console.WriteLine(p.Name);
                }
    
                Console.ReadLine();
            }
        }
    }

    [1] https://msdn.microsoft.com/de-de/library/kyaxdd3x%28v=vs.110%29.aspx

    Wir hoffen, vielen Besuchern der MSDN Foren durch das Posten dieses Problems und einer möglichen Lösung weiterhelfen zu können.

    Viele Grüße,
    Henning Dieterichs
    Entwickler-Hotline für MSDN Online Deutschland

    Disclaimer:
    Bitte haben Sie Verständnis dafür, dass wir hier auf Rückfragen gar nicht oder nur sehr zeitverzögert antworten können.
    Bitte nutzen Sie für Rückfragen oder neue Fragen den telefonischen Weg über die MSDN-Entwickler-Hotline: http://www.msdn-online.de/Hotline
    MSDN-Entwickler-Hotline: Schnelle & kompetente Hilfe für Entwickler: kostenfrei!

    Es gelten für die MSDN-Entwickler-Hotline und dieses Posting diese Nutzungsbedingungen , Hinweise zu Markenzeichen, Informationen zur Datensicherheit sowie die gesonderten Nutzungsbedingungen für die MSDN-Entwickler-Hotline .

    Dienstag, 26. Mai 2015 12:57

Alle Antworten

  • Hallo Henning,

    Vielen Dank für das aufschlussreiche Verfahren, das Sie mitgeteilt haben.

    Gruß

    Aleksander


    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „IT-Pros helfen IT-Pros“ beruht,  kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Mittwoch, 27. Mai 2015 08:17