2009-05-09 12 views
16

Mam usług WCF, który przechodzi wokół aktualizacje statusu poprzez struct tak:Dlaczego funkcja WPF obsługuje wiązanie z właściwościami obiektu, ale nie pola?

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

I narazić właściwość w ViewModel tak:

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

I XAML tak:

<TextBox Text="{Binding CurrentStatus.Total}" /> 

Po uruchomieniu aplikacji widzę błędy w oknie wyjściowym wskazujące, że nie można znaleźć właściwości Total. Sprawdziłem i dwukrotnie sprawdziłem i wpisałem go poprawnie. Przyszło mi do głowy, że błędy wyraźnie wskazują, że nie można znaleźć "właściwości". Dodanie właściwości do struktury sprawiło, że działało to dobrze. Ale wydaje mi się to dziwne, że WPF nie może obsłużyć jednokierunkowego wiązania z polami. Syntaktycznie uzyskujesz dostęp do nich w kodzie i wydaje się głupio, że musisz utworzyć niestandardowy model widoku tylko dla struktury StatusInfo. Czy przeoczyłem coś o wiązaniu WPF? Czy możesz powiązać pole lub czy własność jest wiążąca w jedyny sposób?

Odpowiedz

21

Oprawa ogólnie nie działa na polach. Najbardziej wiążące oparte jest po części na modelu ComponentModel PropertyDescriptor, który (domyślnie) działa na właściwościach. Umożliwia to powiadomienia, sprawdzanie poprawności itp. (Z których żadna nie działa z polami).

Z innych powodów niż mogę się udać, publiczne pola to zły pomysł. Powinny być własnością, faktem. Podobnie, zmienne struktury są złym pomysłem. Co więcej, chroni przed nieoczekiwaną utratą danych (zwykle związaną z mutable structs). To powinno być klasą:

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

Będzie teraz zachowują się jak myślisz powinno. Jeśli chcesz, aby być niezmienne struct, że byłoby OK (ale dane wiążące byłaby tylko jedna droga, oczywiście):

[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; 
    } 
} 

Jednak najpierw pytanie dlaczego jest to struct na pierwszym miejscu. Jest bardzo rzadkie bardzo rzadkie napisać struct w językach .NET. Należy pamiętać, że warstwa proxy "mex" WCF utworzy ją mimo wszystko jako klasę dla użytkownika (chyba że korzystasz z udostępniania zespołów).


W odpowiedzi na "dlaczego stosowanie" post elemencie ("unknown (Google)"):

Jeśli to jest odpowiedź na moje pytanie, to jest źle na wiele sposobów. Po pierwsze, typy wartości jako zmienne są zwykle przydzielane (pierwsze) na stosie. Jeśli zostaną one pchnięte na stertę (na przykład w tablicy/liście), nie ma dużej różnicy w obciążeniu klasy - niewielki fragment nagłówka obiektu i odniesienie. Struktury powinny zawsze być małe. Coś z wieloma polami będzie zbyt duże i albo zamorduje twój stos, albo spowoduje spowolnienie z powodu blendingu. Dodatkowo, struktury powinny być niezmienne - chyba, że ​​naprawdę wiesz, co robisz.

Prawie wszystko, co reprezentuje obiekt, powinno być odporne.

Jeśli trafiasz na bazę danych, prędkość klasy w porównaniu z klasą nie jest problemem w porównaniu do wychodzenia poza proces i prawdopodobnie przez sieć.Nawet jeśli jest nieco wolniejszy, to nic nie znaczy w porównaniu do punktu, w którym jest to właściwe - to znaczy traktowanie obiektów jako obiektów.

W niektórych danych ponad 1M obiektów:

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

podstawie poniższego (różnica prędkości jest alokacji obiektu, a nie polu vs własności). Tak więc około 5 razy wolniej, ale wciąż bardzo, bardzo szybko. Ponieważ to nie będzie wąskie gardło, nie optymalizuj go przedwcześnie!

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

Jako programista C++ uważam, że twoje komentarze są bardzo trudne do zrozumienia. Wydaje mi się też, że dochodzę do różnych wniosków. Na przykład mówisz: "Więc około 5 razy wolniej, ale nadal bardzo, bardzo szybko". Podczas gdy widzę to jako "Wykorzystanie struktur jest około 5 razy szybsze, ale nadal bardzo, bardzo powolne." –

+7

@Daniel westchnienie, znowu zaczynamy: "C++ jest szybszy niż wszystko, zawsze i musi być używany przez cały czas" (westchnienie). W szerokiej gamie zastosowań nie ma znaczącej różnicy, z wyjątkiem jednej znacznie łatwiejszej do uzyskania. –

+0

Nigdy nie powiedziałem, że C++ jest szybszy! Podsumowując takie wskazywały, że masz poważne uprzedzenia (lub może nieporozumienia). "W szerokiej gamie aplikacji nie ma znaczącej różnicy, z wyjątkiem jednej, która jest znacznie łatwiejsza do uzyskania" - zgadzamy się, chociaż C++ może być szybsze, nie jest to ważne - jednak C++ ułatwia to, to jest znaczące. A może po prostu źle zinterpretowałem to, co powiedziałeś, żeby poprzeć moją argumentację ... W rzeczy samej, westchnij. –

0

mogę się tylko domyślać, dlaczego oni obsługują tylko właściwości: może dlatego, że wydaje się być uniwersalna konwencja w ramach .NET nigdy wystawiać pola zmienny (probably to safeguard binary compatibility) i oczekuje się, że jakoś wszyscy programiści śledzić takie same Konwencja.

Ponadto, mimo że pola i właściwości są dostępne przy użyciu tej samej składni, powiązanie danych wykorzystuje odbicie, a (jak słyszałem) odbicie musi być używane inaczej w celu uzyskania dostępu do pól niż uzyskania dostępu do właściwości.