2009-05-09 16 views
16

Tôi đã có một dịch vụ WCF mà đi xung quanh cập nhật trạng thái thông qua một cấu trúc như sau:Tại sao WPF hỗ trợ ràng buộc với các thuộc tính của một đối tượng, nhưng không phải là các trường?

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

tôi tiếp xúc với một tài sản trong một ViewModel như thế này:

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

Và XAML như vậy:

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

Khi tôi chạy ứng dụng tôi thấy lỗi trong cửa sổ đầu ra cho biết không thể tìm thấy Tổng số thuộc tính. Tôi đã kiểm tra và kiểm tra lại và tôi đã nhập chính xác. Nó xảy ra với tôi rằng các lỗi đặc biệt chỉ ra rằng 'tài sản' không thể được tìm thấy. Vì vậy, thêm một thuộc tính vào cấu trúc làm cho nó hoạt động tốt. Nhưng điều này có vẻ kỳ quặc với tôi rằng WPF không thể xử lý một chiều ràng buộc với các trường. Cú pháp bạn truy cập chúng giống nhau trong mã và có vẻ ngớ ngẩn khi phải tạo một mô hình khung nhìn tùy chỉnh chỉ cho cấu trúc StatusInfo. Tôi đã bỏ lỡ một cái gì đó về WPF ràng buộc? Bạn có thể liên kết với một lĩnh vực hoặc là tài sản ràng buộc cách duy nhất?

Trả lời

21

Ràng buộc thường là không hoạt động với các trường. Hầu hết các ràng buộc dựa trên một phần, trên mô hình ComponentModel PropertyDescriptor, theo mặc định, nó hoạt động trên các thuộc tính. Điều này cho phép thông báo, xác nhận, v.v. (không cái nào trong số đó hoạt động với các trường).

Vì nhiều lý do hơn tôi có thể tham gia, các trường công khai là một ý tưởng tồi. Họ nên là tài sản, thực tế. Tương tự, các cấu trúc có thể biến đổi là một ý tưởng tồi rất. Không kém, nó bảo vệ chống mất dữ liệu bất ngờ (thường được kết hợp với cấu trúc có thể thay đổi). Đây phải là một lớp học:

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

Bây giờ nó sẽ hoạt động như bạn nghĩ. Nếu bạn muốn nó được một bất biến struct, đó sẽ là OK (nhưng dữ liệu ràng buộc sẽ chỉ có một chiều, tất nhiên):

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

Tuy nhiên, tôi sẽ câu hỏi đầu tiên tại sao đây là một struct ngay từ đầu. Đó là rất hiếm để viết cấu trúc bằng ngôn ngữ .NET. Hãy nhớ rằng lớp proxy "mex" WCF sẽ tạo ra nó như là một lớp ở người tiêu dùng anyway (trừ khi bạn sử dụng chia sẻ lắp ráp).


Trong câu trả lời cho "tại sao sử dụng cấu trúc" trả lời ("không rõ (google)"):

Nếu đó là một câu trả lời cho câu hỏi của tôi, nó là sai trong nhiều cách khác nhau. Đầu tiên, các loại giá trị là biến số thường được phân bổ (đầu tiên) trên ngăn xếp. Nếu chúng được đẩy lên đống (ví dụ trong một mảng/danh sách) thì không có nhiều sự khác biệt về chi phí từ một lớp - một chút tiêu đề đối tượng cộng với một tham chiếu. Các bản vẽ phải luôn là nhỏ. Một cái gì đó với nhiều lĩnh vực sẽ được quá kích thước, và sẽ hoặc là giết chết stack của bạn hoặc chỉ gây chậm đi do blitting. Ngoài ra, cấu trúc nên không thay đổi - trừ khi bạn thực sự biết bạn đang làm gì.

Khá nhiều thứ đại diện cho một đối tượng nên là điều bất động.

Nếu bạn đang truy cập cơ sở dữ liệu, tốc độ của cấu trúc so với lớp không phải là vấn đề so với quá trình ngoài quy trình và có thể qua mạng.Ngay cả khi nó chậm hơn một chút, điều đó có nghĩa là không có gì so với điểm nhận được nó đúng - tức là xử lý các đối tượng như đối tượng.

Như một số số liệu trên 1M đối tượng:

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

dựa trên như sau (phần chênh lệch tốc độ trong phân bổ đối tượng, không phải lĩnh vực vs tài sản). Vì vậy, khoảng 5x chậm hơn, nhưng vẫn còn rất, rất nhanh. Vì đây không phải là nút cổ chai của bạn, đừng sớm tối ưu hóa điều này!

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

Là một lập trình viên C++, tôi nhận thấy các nhận xét của bạn ở trên rất khó hiểu. Tôi cũng dường như đi đến kết luận khác nhau. Ví dụ, bạn nói, "Vì vậy, về 5x chậm hơn, nhưng vẫn rất, rất nhanh chóng." Trong khi tôi thấy nó như là, "Việc sử dụng các cấu trúc là khoảng 5x nhanh hơn, nhưng vẫn còn rất, rất chậm." –

+7

@Daniel thở dài, ở đây chúng tôi đi một lần nữa, "C++ nhanh hơn tất cả mọi thứ, bao giờ hết, và phải được sử dụng mọi lúc" (tiếng thở dài). Trong một loạt các ứng dụng không có sự khác biệt đáng kể, khác hơn là một được dễ dàng hơn đáng kể để có được quyền. –

+0

Tôi chưa bao giờ nói C++ nhanh hơn! Kết luận như vậy chỉ ra rằng bạn có một số định kiến ​​nghiêm trọng (hoặc có thể là quan niệm sai lầm). "Trong nhiều ứng dụng khác nhau, không có sự khác biệt đáng kể, ngoài việc dễ dàng hơn để có được quyền" - vì vậy chúng tôi đồng ý, mặc dù C++ có thể nhanh hơn, điều này không quan trọng - tuy nhiên, C++ giúp bạn dễ dàng hơn điều này là quan trọng. Hoặc có lẽ tôi chỉ hiểu sai những gì bạn nói để ủng hộ lập luận của tôi ... Thực sự là Sigh. –

0

Tôi chỉ có thể đoán tại sao họ chỉ hỗ trợ thuộc tính: có lẽ vì nó có vẻ là một quy ước phổ quát trong khuôn khổ NET không bao giờ để lộ các lĩnh vực có thể thay đổi (probably to safeguard binary compatibility), và họ bằng cách nào đó dự kiến ​​tất cả các lập trình viên đi theo cùng quy ước.

Ngoài ra, mặc dù các trường và thuộc tính được truy cập với cùng cú pháp, ràng buộc dữ liệu sử dụng sự phản chiếu và (vì vậy tôi đã nghe) phản ánh phải được sử dụng khác nhau để truy cập các trường hơn là truy cập thuộc tính.

Các vấn đề liên quan