2009-05-09 5 views
16

Ich habe einen WCF-Dienst bekam, die über eine Struktur wie so um Status-Updates passiert:Warum unterstützt WPF die Bindung an Eigenschaften eines Objekts, aber nicht an Felder?

[DataContract] 
public struct StatusInfo 
{ 
    [DataMember] public int Total; 
    [DataMember] public string Authority; 
} 
... 
public StatusInfo GetStatus() { ... } 

ich aussetzen eine Eigenschaft in einem Ansichtsmodell wie folgt aus:

public class ServiceViewModel : ViewModel 
{ 
    public StatusInfo CurrentStatus 
    { 
     get{ return _currentStatus; } 
     set 
     { 
      _currentStatus = value; 
      OnPropertyChanged(() => CurrentStatus); 
     } 
    }  
} 

Und XAML wie so:

Beim Ausführen der App sehe ich Fehler im Ausgabefenster, die anzeigen, dass die Total-Eigenschaft nicht gefunden werden kann. Ich überprüfte und überprüfte es und tippte es korrekt. Es ist mir aufgefallen, dass die Fehler spezifisch anzeigen, dass die "Eigenschaft" nicht gefunden werden kann. Das Hinzufügen einer Eigenschaft zur Struktur hat also gut funktioniert. Aber das scheint mir seltsam zu sein, dass WPF nicht mit unidirektionaler Bindung an Felder umgehen kann. Syntaktisch greifen Sie auf dieselben im Code zu und es scheint albern, ein benutzerdefiniertes Ansichtsmodell nur für die StatusInfo-Struktur erstellen zu müssen. Habe ich etwas über WPF-Bindung verpasst? Kannst du dich an ein Feld binden oder ist das nur die Bindung von Eigenschaften?

Antwort

21

Bindung im Allgemeinen funktioniert nicht auf Felder. Die meisten Bindungen basieren zum Teil auf dem Modell ComponentModel PropertyDescriptor, das (standardmäßig) auf Eigenschaften funktioniert. Dies ermöglicht Benachrichtigungen, Validierung usw. (keine davon funktioniert mit Feldern).

Aus mehr Gründen, als ich hineingehen kann, sind öffentliche Felder eine schlechte Idee. Sie sollten Eigenschaften, Fakten sein. Ebenso sind veränderbare Strukturen eine schlechte Idee. Nicht zuletzt schützt es vor unerwartetem Datenverlust (der häufig mit veränderbaren Strukturen verbunden ist). Dies sollte eine Klasse sein:

[DataContract] 
public class StatusInfo 
{ 
    [DataMember] public int Total {get;set;} 
    [DataMember] public string Authority {get;set;} 
} 

Es wird sich jetzt so verhalten, wie Sie denken, dass es sollte. Wenn Sie es wünschen eine unveränderlich Struktur zu sein, das wäre in Ordnung sein (aber Datenbindung würde nur ein Weg sein, natürlich):

[DataContract] 
public struct StatusInfo 
{ 
    [DataMember] public int Total {get;private set;} 
    [DataMember] public string Authority {get;private set;} 

    public StatusInfo(int total, string authority) : this() { 
     Total = total; 
     Authority = authority; 
    } 
} 

Allerdings würde ich erste Frage, warum dies eine Struktur ist an erster Stelle. Es ist sehr selten eine Struktur in .NET-Sprachen zu schreiben. Beachten Sie, dass der WCF-Proxy-Layer "mex" diese beim Kunden als Klasse erstellt (sofern Sie die Baugruppenfreigabe nicht verwenden).


In Antwort auf die "Warum Verwendung structs" Antwort ("unknown (google)"):

Wenn das eine Antwort auf meine Frage ist, ist es falsch, in vielerlei Hinsicht. Zuerst werden Werttypen als Variablen gemeinsam (zuerst) auf dem Stapel zugeordnet. Wenn sie auf den Heap geschoben werden (zum Beispiel in einem Array/einer Liste), gibt es nicht viel Unterschied im Overhead von einer Klasse - ein kleines Stück Objektheader plus eine Referenz. Structs sollten immer small sein. Etwas mit mehreren Feldern wird überdimensioniert sein und entweder deinen Stack umbringen oder aufgrund des Blittings langsam werden. Darüber hinaus sollten Strukturen unveränderlich sein - außer Sie wirklich wissen, was Sie tun.

So ziemlich alles, was ein Objekt darstellt, sollte unveränderlich sein.

Wenn Sie eine Datenbank treffen, ist die Geschwindigkeit von struct vs class kein Problem, im Gegensatz zu Out-of-Process und wahrscheinlich über das Netzwerk.Selbst wenn es etwas langsamer ist, bedeutet das nichts im Vergleich zu dem Punkt, es richtig zu machen - d. H. Objekte als Objekte zu behandeln.

Da einige Metriken über 1M Objekte:

struct/field: 50ms 
class/property: 229ms 

basierend auf dem folgende (die Geschwindigkeitsdifferenz ist in Zuordnung Objekt, nicht Feld vs Eigentum). Also etwa 5x langsamer, aber immer noch sehr, sehr schnell. Da dies nicht Ihr Flaschenhals sein wird, optimieren Sie dies nicht vorzeitig!

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
struct MyStruct 
{ 
    public int Id; 
    public string Name; 
    public DateTime DateOfBirth; 
    public string Comment; 
} 
class MyClass 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public DateTime DateOfBirth { get; set; } 
    public string Comment { get; set; } 
} 
static class Program 
{ 
    static void Main() 
    { 
     DateTime dob = DateTime.Today; 
     const int SIZE = 1000000; 
     Stopwatch watch = Stopwatch.StartNew(); 
     List<MyStruct> s = new List<MyStruct>(SIZE); 
     for (int i = 0; i < SIZE; i++) 
     { 
      s.Add(new MyStruct { Comment = "abc", DateOfBirth = dob, 
        Id = 123, Name = "def" }); 
     } 
     watch.Stop(); 
     Console.WriteLine("struct/field: " 
        + watch.ElapsedMilliseconds + "ms"); 

     watch = Stopwatch.StartNew(); 
     List<MyClass> c = new List<MyClass>(SIZE); 
     for (int i = 0; i < SIZE; i++) 
     { 
      c.Add(new MyClass { Comment = "abc", DateOfBirth = dob, 
        Id = 123, Name = "def" }); 
     } 
     watch.Stop(); 
     Console.WriteLine("class/property: " 
        + watch.ElapsedMilliseconds + "ms"); 
     Console.ReadLine(); 
    } 
} 
+4

Als C++ Programmierer finde ich Ihre Kommentare oben sehr schwer zu ergründen. Ich komme auch zu anderen Schlussfolgerungen. Zum Beispiel sagst du: "Also ungefähr 5x langsamer, aber immer noch sehr, sehr schnell." Während ich es als "Die Verwendung von Strukturen ist etwa 5x schneller, aber immer noch sehr, sehr langsam." –

+7

@Daniel Seufz, hier gehen wir wieder, "C++ ist schneller als alles, immer, und muss zu jeder Zeit verwendet werden" (Seufzer). In einer Vielzahl von Anwendungen gibt es keinen nennenswerten Unterschied, abgesehen davon, dass einer wesentlich leichter zu korrigieren ist. –

+0

Ich habe nie gesagt, C++ war schneller! Abschließend hat dies gezeigt, dass Sie einige Vorurteile (oder vielleicht Missverständnisse) haben. "In einer Vielzahl von Anwendungen gibt es keinen nennenswerten Unterschied, abgesehen davon, dass es wesentlich einfacher ist, in Ordnung zu kommen" - also sind wir uns einig, obwohl C++ vielleicht schneller ist, ist das nicht wichtig - C++ macht es jedoch leichter, es richtig zu machen das ist signifikant. Oder vielleicht habe ich nur falsch interpretiert, was du gesagt hast, um meine Argumentation zu unterstützen ... Seufz in der Tat. –

0

Ich kann nur vermuten, warum sie nur Eigenschaften unterstützen: vielleicht, weil es sich um eine Universal-Konvention in dem .NET-Framework zu sein scheint nie veränderbare Felder (probably to safeguard binary compatibility) freizulegen, und sie erwartet irgendwie alle Programmierer die gleiche folgen Konvention.

Auch wenn auf Felder und Eigenschaften mit der gleichen Syntax zugegriffen wird, verwendet Datenbindung Reflexion, und (so habe ich gehört) Reflexion muss anders verwendet werden, um auf Felder zuzugreifen, als auf Eigenschaften zuzugreifen.