为什么WPF支持绑定到对象的属性,而不支持字段?

Pau*_*der 21 .net wpf binding field

我有一个WCF服务,通过如下结构传递状态更新:

[DataContract]
public struct StatusInfo
{
    [DataMember] public int Total;
    [DataMember] public string Authority;
}
...
public StatusInfo GetStatus() { ... }
Run Code Online (Sandbox Code Playgroud)

我在ViewModel中公开了一个属性,如下所示:

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

和XAML一样:

<TextBox Text="{Binding CurrentStatus.Total}" />
Run Code Online (Sandbox Code Playgroud)

当我运行应用程序时,我在输出窗口中看到错误,指示无法找到Total属性.我检查并仔细检查,我输入正确.我突然意识到错误明确表明找不到"财产".因此,向结构添加属性使其工作得很好.但这对我来说似乎很奇怪,WPF无法处理对字段的单向绑定.从语法上讲,您在代码中访问它们是相同的,并且仅为StatusInfo结构创建自定义视图模型似乎很愚蠢.我错过了WPF绑定的一些内容吗?你能绑定到一个字段还是属性绑定唯一的方法?

Mar*_*ell 29

绑定通常不适用于字段.大多数绑定部分基于ComponentModel PropertyDescriptor模型,该模型(默认情况下)适用于属性.这使得通知,验证等(没有一个适用于字段).

出于更多原因,公共领域是一个坏主意.它们应该是属性,事实.同样,可变结构是一个非常糟糕的主意.尤其是,它可以防止意外数据丢失(通常与可变结构相关).这应该是一个类:

[DataContract]
public class StatusInfo
{
    [DataMember] public int Total {get;set;}
    [DataMember] public string Authority {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

它现在将按照您的想法行事.如果你想让它成为一个不可变的结构,那就没关系(但数据绑定当然只有单向):

[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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我首先要问的是为什么这是一个结构体.用.NET语言编写结构是非常罕见的.请记住,WCF"mex"代理层无论如何都会将其创建为消费者的类(除非您使用程序集共享).


在回答"为什么使用结构"回复("unknown(google)")时:

如果这是对我的问题的回复,那在很多方面都是错误的.首先,作为变量的值类型通常在堆栈上分配(第一个).如果将它们推入堆(例如在数组/列表中),则类的开销与一小部分对象头加上引用没有太大区别.结构应该总是很小.具有多个字段的某些内容将会过大,并且会导致您的堆栈被谋杀或者由于blitting而导致缓慢.另外,结构应该是不可变的 - 除非你真的知道你在做什么.

几乎任何代表对象的东西都应该是不可动摇的.

如果您正在访问数据库,那么与进程外和可能通过网络相比,结构与类的速度是无问题的.即使它有点慢,但这与正确的方法相比毫无意义 - 即将对象视为对象.

作为超过1M对象的一些指标:

struct/field: 50ms
class/property: 229ms
Run Code Online (Sandbox Code Playgroud)

基于以下内容(速度差异在对象分配中,而不是字段与属性).因此大约慢了5倍,但仍然非常非常快.由于这不会成为你的瓶颈,不要过早地优化它!

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Daniel叹了口气,我们再来一次,"C++比任何时候都快,而且必须随时使用"(叹气).在各种各样的应用中,没有明显的差异,除了一个明显更容易正确. (10认同)
  • 作为一名C++程序员,我发现你上面的评论非常难以理解.我似乎也得出了不同的结论.例如,你说,"所以大约慢了5倍,但仍然非常非常快." 而我认为,"结构的使用速度提高了约5倍,但仍然非常非常慢." (5认同)
  • 您的性能测试可能太短,无法正确测量GC开销.试试这个测试的修改:http://pastebin.com/Ajkj0hdm - 现在类慢了12倍,因为80%的时间花在了GC上.现在将SIZE调高至10M并观察"私有字节":结构为200 MB,上升到1 GB. (3认同)
  • @Daniel也许我误解了您的意思,“作为一名C ++程序员……但仍然非常非常慢” (2认同)