Samstag, Dezember 14, 2019

`- Typ.GetProperties` – Eigenschaft, um

Kurze Version

In der MSDN-Dokumentation für - Typ.GetProperties besagt, dass die collection gibt es nicht garantiert ist, werden in alphabetischer Reihenfolge oder in der Reihenfolge der Deklaration, obwohl läuft ein einfacher test zeigt, dass im Allgemeinen wird es wieder in der Reihenfolge der Deklaration. Gibt es bestimmte Szenarien, die Sie kennen, wo dies nicht der Fall ist? Darüber hinaus, was ist die empfohlene alternative?

Ausführliche Version

Erkenne ich die MSDN-Dokumentation für - Typ.GetProperties Staaten:

Der GetProperties-Methode nicht zurück, Eigenschaften, die in einer bestimmten
um, wie alphabetisch oder in der Reihenfolge der Deklaration. Ihr code muss nicht
hängt von der Reihenfolge, in der die Eigenschaften zurückgegeben werden, weil
Reihenfolge variiert.

also es gibt keine Garantie, dass die Sammlung von der Methode zurückgegeben werden, bestellt jede spezifische Art und Weise. Basierend auf einigen tests, die ich gefunden habe, im Gegenteil, dass die zurückgegebenen Eigenschaften erscheinen in der Reihenfolge, wie Sie definiert sind in der Typ.

Beispiel:

class Simple
{
    public int FieldB { get; set; }
    public string FieldA { get; set; }
    public byte FieldC { get; set; }
}
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Simple Properties:");
        foreach (var propInfo in typeof(Simple).GetProperties())
            Console.WriteLine("\t{0}", propInfo.Name);
    }
}

Ausgabe:

Simple Properties:
        FieldB
        FieldA
        FieldC

Einem solchen Fall, dass dieser unterscheidet sich nur geringfügig ist, wenn der Typ in Frage, die ein Elternteil hat, der hat auch Eigenschaften:

class Parent
{
    public int ParentFieldB { get; set; }
    public string ParentFieldA { get; set; }
    public byte ParentFieldC { get; set; }
}

class Child : Parent
{
    public int ChildFieldB { get; set; }
    public string ChildFieldA { get; set; }
    public byte ChildFieldC { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Parent Properties:");
        foreach (var propInfo in typeof(Parent).GetProperties())
            Console.WriteLine("\t{0}", propInfo.Name);

        Console.WriteLine("Child Properties:");
        foreach (var propInfo in typeof(Child).GetProperties())
            Console.WriteLine("\t{0}", propInfo.Name);

    }
}

Ausgabe:

Parent Properties:
        ParentFieldB
        ParentFieldA
        ParentFieldC
Child Properties:
        ChildFieldB
        ChildFieldA
        ChildFieldC
        ParentFieldB
        ParentFieldA
        ParentFieldC

Was bedeutet, dass die GetProperties Methode geht die Vererbungskette von unten nach oben bei der Entdeckung der Eigenschaften. Das ist in Ordnung und kann als solche behandelt.

Fragen:

  1. Gibt es bestimmte Situationen, in denen das beschriebene Verhalten abweichen würde, die ich verpasst habe?
  2. Wenn je nach Auftrag wird nicht empfohlen, was dann ist die empfohlene Vorgehensweise?

Eine scheinbar naheliegende Lösung wäre, um ein benutzerdefiniertes Attribut, das anzeigt, in welcher Reihenfolge die Eigenschaften sollte erscheinen (Ähnlich wie die Order Eigenschaft auf die DataMember – Attribut). So etwas wie:

public class PropOrderAttribute : Attribute
{
    public int SeqNbr { get; set; }
}

Und dann umsetzen wie:

class Simple
{
    [PropOrder(SeqNbr = 0)]
    public int FieldB { get; set; }
    [PropOrder(SeqNbr = 1)]
    public string FieldA { get; set; }
    [PropOrder(SeqNbr = 2)]
    public byte FieldC { get; set; }
}

Aber so viele gefunden haben, dies wird zu einem ernsthaften problem Wartung, wenn Ihr Typ hat 100 Eigenschaften und man muss hinzufügen, einen zwischen dem ersten 2.

UPDATE

Die hier gezeigten Beispiele sind einfach nur für demonstrative Zwecke. In meinem speziellen Szenario, definiere ich eine message-format mit einer Klasse, dann Durchlaufen Sie die Eigenschaften der Klasse und schnappen Sie sich Ihre Attribute, um zu sehen, wie ein bestimmtes Feld in der Nachricht sollte demarshaled. Die Reihenfolge der Felder in der Nachricht ist bedeutsam, so ist die Reihenfolge der Eigenschaften in meiner Klasse muss erheblich sein.

Es funktioniert derzeit nur durch Iteration über die Rückkehr Sammlung von GetProperties, aber seit Sie in der Dokumentation heißt es, es wird nicht empfohlen, ich war auf der Suche, um zu verstehen, warum und welche andere Optionen habe ich?

  • Was wollen Sie erreichen? Warum brauchen Sie einen Auftrag? Vielleicht gibt es eine andere Möglichkeit
  • Grundsätzlich ist die Dokumentation sagt: „verlassen Sie sich nicht auf eine Bestellung“, aber in der aktuellen Implementierung wird es wohl auch haben, eine konsistente Reihenfolge. Die Dokumentation ist präzise, „verlassen Sie sich nicht auf eine Bestellung“ bedeutet nicht „es wird variieren“. Es bedeutet „es könnte variieren“. Q1: können Sie nicht davon ausgehen, es wird immer so sein, wie du beschrieben hast wieder. Q2: verlassen Sie sich nicht auf eine Bestellung. Um es sich selbst, wenn Sie brauchen eine geordnete Liste.
  • 1. Sie völlig nicht abhängig sein sollten von der Reihenfolge der Deklaration – das ist sicher, da es hängt von der Implementierung der Laufzeitumgebung (es könnte sogar von version zu version).
  • 2.Warum nicht Sie Sortieren Eigenschaften alphabetisch? Oder brauchen Sie eine andere Sorte bestellen?
  • Ich habe aktualisiert die Frage mit dem Zusammenhang mit der Frage. Welche alternativen habe ich?
  • Wie ich schon sagte, wenn Sie brauchen, konsistente Reihenfolge, um Sie mit Namen. Oder lagern Sie die Feldnamen zusammen mit den Werten

InformationsquelleAutor M.Babcock | 2012-01-15

5 Kommentare

  1. 14

    Die Reihenfolge ist einfach nicht garantiert; was auch immer passiert…. Passiert.

    Offensichtlichen Fällen, wo es sich ändern könnte:

    • alles, was implementiert ICustomTypeDescriptor
    • alles mit einem TypeDescriptionProvider

    Aber ein subtiler Fall: partielle Klassen. Wenn eine Klasse aufgeteilt auf mehrere Dateien, die Reihenfolge der Ihre Nutzung ist gar nicht definiert. Sehen Ist die „textuelle, um“ über die partielle Klassen formal definiert?

    Natürlich, es ist nicht definiert, auch für ein einzelnes (nicht-Teil -) definition ;p

    Aber vorstellen,

    Datei 1

    partial class Foo {
         public int A {get;set;}
    }

    Datei 2

    partial class Foo {
        public int B {get;set:}
    }

    Gibt es keine offizielle Erklärung, um hier zwischen A und B. Siehe den verlinkten post zu sehen, wie es neigt geschehen, obwohl.


    Re edit; der beste Ansatz ist noch anzugeben, der Marschall-info separat; ein gemeinsamer Ansatz wäre, um ein benutzerdefiniertes Attribut, das dauert ein numerischer Reihenfolge, und dekorieren Sie den Mitgliedern mit, dass. Sie können dann um basierend auf dieser Nummer. protobuf-net macht etwas sehr ähnliches, und ehrlich gesagt, ich würde vorschlagen, mit einem vorhandenen Serialisierungs-Bibliothek hier:

    [ProtoMember(n)]
    public int Foo {get;set;}

    Wobei „n“ eine ganze Zahl ist. Im Fall von protobuf-net speziell, gibt es auch eine API geben Sie diese zahlen auch GESONDERT, was nützlich ist, wenn der Typ nicht unter Ihrer direkten Kontrolle.

    • Das sind gute Punkte. Was ist die alternative dann?
    • was ist die alternative? Sie hat ausdrücklich erklärt: verlassen Sie sich nicht auf, um
    • Ich aktualisiert meine Frage mit die Details von dem, was ich bin versucht zu erreichen.
    • Danke für die Klarstellung.
    • Die ProtoMember(n) Idee ist nett, und es gibt eine evolution, die Idee, die verwendet reflektion, um die Bestellnummer automatisch anhand der Zeilennummer, so wird es erläutert im diese Antwort.
  2. 5

    Ich verwende benutzerdefinierte Attribute hinzufügen, um die erforderlichen Metadaten selbst (es ist mit einem REST, wie service, verbraucht und gibt CRLF getrennte Key=Value-Paaren.

    Zunächst ein benutzerdefiniertes Attribut:

    class ParameterOrderAttribute : Attribute
    {
        public int Order { get; private set; }
        public ParameterOrderAttribute(int order)
        {
            Order = order;
        }
    }

    Dann schmücken Sie Ihre Klassen:

    class Response : Message
    {
        [ParameterOrder(0)]
        public int Code { get; set; }
    }
    
    class RegionsResponse : Response 
    {
        [ParameterOrder(1)]
        public string Regions { get; set; }
    }
    
    class HousesResponse : Response
    {
        public string Houses { get; set; }
    }

    Eine praktische Methode für die Konvertierung einer PropertyInfo in eine sortierbare int:

        private int PropertyOrder(PropertyInfo propInfo)
        {
            int output;
            var orderAttr = (ParameterOrderAttribute)propInfo.GetCustomAttributes(typeof(ParameterOrderAttribute), true).SingleOrDefault();
            output = orderAttr != null ? orderAttr.Order : Int32.MaxValue;
            return output;
        }

    Besser noch, schreiben ist wie eine Erweiterung:

    static class PropertyInfoExtensions
    {
        private static int PropertyOrder(this PropertyInfo propInfo)
        {
            int output;
            var orderAttr = (ParameterOrderAttribute)propInfo.GetCustomAttributes(typeof(ParameterOrderAttribute), true).SingleOrDefault();
            output = orderAttr != null ? orderAttr.Order : Int32.MaxValue;
            return output;
        }
    }

    Schließlich können Sie nun Ihre Abfrage Typ Objekt:

            var props = from p in type.GetProperties()
                        where p.CanWrite
                        orderby p.PropertyOrder() ascending
                        select p;
    • Sehr schöne, vollständige Antwort 🙂 Wünsche das markiert war, als die Antwort für die nächste person auf der Suche…
    • Danke! Einfach nochmals Lesen, keine Zeit zum Bearbeiten ist es jetzt aber GetOrder() wäre eine sehr schöne Erweiterung Methode PropertyInfo. Dann wäre es orderby p.Order() ascending und man würde sich keine sorgen über Umfang.
  3. 4

    Sich auf eine Implementierung detail, die explizit dokumentiert als nicht garantiert ist ein Rezept für eine Katastrophe.

    Den „empfohlen“ – Ansatz würde variieren je nachdem, was Sie tun möchten, mit diesen Eigenschaften, sobald Sie Sie haben. Nur die Anzeige auf dem Bildschirm? MSDN docs group by-Element (Eigenschaft, Bereich, Funktion) und dann alphabetisch innerhalb der Gruppen.

    Wenn Sie Ihre message-format basiert auf der Reihenfolge der Felder, dann müssten Sie entweder:

    1. Angeben, die erwartet, um in irgendeine Art von message-definition. Google protocol buffers funktioniert auf diese Weise, wenn ich mich erinnere – die message-definition kompiliert wird in diesem Fall aus einer .proto-Datei in eine code-Datei für die Verwendung in welcher Sprache auch immer Sie passieren, mit zu arbeiten.

    2. Verlassen Sie sich auf eine Bestellung, können unabhängig voneinander generiert werden, z.B. alphabetisch.

    • Ich aktualisiert meine Frage mit mehr Einzelheiten darüber, warum die Eigenschaft Reihenfolge ist wichtig in meiner situation.
  4. 4

    1:

    Ich habe in den letzten Tag der Behandlung eines Problems in einem MVC 3-Projekt, und Sie alle kamen zu diesem speziellen problem. Es ist im Grunde stützte sich auf die Eigenschaft, um die gleichen in der gesamten session, aber bei manchen Anlässen ein paar der Eigenschaften, die die Plätze getauscht, vermasselt der Website.

    Zuerst der code aufgerufen Type.GetProperties() zu definieren Spaltennamen in einer dynamischen jqGrid Tabelle, etwas, dass in diesem Fall tritt einmal pro page_load. Nachfolgende Zeiten der Type.GetProperties() – Methode aufgerufen wurde, war zum Auffüllen der tatsächlichen Daten für die Tabelle, und in einigen seltenen Fällen sind die Eigenschaften, die die Plätze getauscht und vermurkst die Präsentation komplett. In einigen Fällen sind weitere Eigenschaften, die die Website verlassen, für eine hierarchische subgrid bekam eingeschaltet ist, d.h. Sie konnte nicht mehr sehen, die sub-Daten, da die ID-Spalte enthielt fehlerhafte Daten. In anderen Worten: ja, das kann definitiv passieren. Hüten Sie sich vor.

    2:

    Wenn Sie müssen konsistent, um in der gesamten system-Sitzung aber nicht nessecarily genau der gleichen Reihenfolge für alle Sitzungen, die Problemumgehung ist tot einfach: speichern Sie die PropertyInfo[] array erhalten Sie von Type.GetProperties() als ein Wert in der webcache oder in einem Wörterbuch mit dem Typ (oder typename) als cache/Wörterbuch Schlüssel. Später, wenn Sie ‚ re zu tun, ein Type.GetProperties() statt Ersatz für HttpRuntime.Cache.Get(Type/Typename) oder Dictionary.TryGetValue(Type/Typename, out PropertyInfo[]). Auf diese Weise werden Sie garantiert immer den Auftrag bekommen, Sie hat die erste Zeit.

    Wenn Sie immer den gleichen Ordnung (d.h. für alle sessions) ich schlage vor, Sie kombinieren die oben erwähnten Ansatz mit irgendeiner Form von Konfigurations-Mechanismus, d.h. die Reihenfolge angeben, in der web.config/app.config, Art der PropertyInfo[] array erhalten Sie von Type.GetProperties() nach der angegebenen Reihenfolge, und speichern Sie es dann in cache/static dictionary.

    • Ich fand, dass jeder Aufruf von GetProperty(„xxx“) würden in der Folge Ursache-Eigenschaft xxx zurückgegeben werden zuerst in der Liste zurückgegeben GetProperties()

Kostenlose Online-Tests

Letzte Fragen

Tun ItemView löst Blase?

Ich habe eine CompositeView für eine Tabelle. Ich habe Trigger-set in der Kind-ItemView für jede Zeile... var TableRow = Marionette.ItemView.extend({ tagName:...

Wie kann ich untersuchen, WCF was 400 bad request über GET?

Die folgenden WCF-endpoint funktioniert gut mit dem WCF test client: AssetList ListFlaggedAssets(short processCode, string platform, string endpoint = "null", string portalId = "null", int...

Bei der Verwendung von UUIDs, sollte ich auch mit AUTO_INCREMENT?

Wir bauen eine neue web-app, die eine offline-iPad - /Android-app-version auf einer Reihe von lokalen Geräten, die Einsätze mit neuen Daten. Als solche benötigen...

Actionscript-Objekt, das verschiedene Eigenschaften

Wie kann ich die Anzahl der Eigenschaften in einer generischen Actionscript-Objekt? (Wie die Array-Länge) InformationsquelleAutor Fragsworth | 2011-01-15

Wie plot mehrere Graphen und nutzen Sie die Navigations-Taste im [matplotlib]

Die neueste version von matplotlib erstellt automatisch Navigations-buttons unter den graph. Aber die Beispiele, die ich finden alles im Internet zeigen, wie erstellen Sie...