我有一个WCF服务,通过如下结构传递状态更新:
[DataContract]
public struct StatusInfo
{
[DataMember] public int Total;
[DataMember] public string Authority;
}
...
public StatusInfo GetStatus() { ... }
我在ViewModel中公开了一个属性,如下所示:
public class ServiceViewModel : ViewModel
{
public StatusInfo CurrentStatus
{
get{ return _currentStatus; }
set
{
_currentStatus = value;
OnPropertyChanged( () => CurrentStatus );
}
}
}
和XAML一样:
<TextBox Text="{Binding CurrentStatus.Total}" />
当我运行应用程序时,我在输出窗口中看到错误,指示无法找到Total属性。我检查并仔细检查,我输入正确。我突然意识到错误明确表明找不到“财产”。因此,向结构添加属性使其工作得很好。但对我来说这似乎很奇怪,WPF无法处理对字段的单向绑定。从语法上讲,您在代码中访问它们是相同的,并且仅为StatusInfo结构创建自定义视图模型似乎很愚蠢。我错过了WPF绑定的一些内容吗?你能绑定到一个字段或是唯一的绑定属性吗?
答案 0 :(得分:28)
绑定通常不适用于字段。大多数绑定部分基于ComponentModel PropertyDescriptor
模型,该模型(默认情况下)适用于属性。这样可以启用通知,验证等(其中任何一个都不适用于字段)。
由于我可以进入的原因更多,公共领域是一个坏主意。它们应该是属性,事实。同样,可变结构是一个非常坏主意。尤其是,它可以防止意外数据丢失(通常与可变结构相关)。这应该是一个类:
[DataContract]
public class StatusInfo
{
[DataMember] public int Total {get;set;}
[DataMember] public string Authority {get;set;}
}
它现在将按照您的想法行事。如果你希望它是一个不可变的结构,那就没问题(但数据绑定当然只有单向):
[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;
}
}
但是,我首先要问的是为什么这是一个结构。用.NET语言编写结构是非常罕见。请记住,WCF“mex”代理层无论如何都会将其创建为消费者的类(除非您使用程序集共享)。
回答“为什么使用结构”回复(“unknown(google)”):
如果这是对我的问题的回复,那在很多方面都是错误的。首先,值类型作为变量通常在堆栈上分配(第一个)。如果将它们推入堆中(例如在数组/列表中),则类的开销与一小部分对象头加上引用没有太大区别。结构应始终小。具有多个字段的某些内容将会过大,并且会导致您的堆栈被谋杀或者由于blitting而导致缓慢。此外,结构应该是不可变的 - 除非你真的知道你在做什么。
几乎所有代表对象的东西都应该是免疫的。
如果您正在访问数据库,那么与进程外和可能通过网络相比,结构与类的速度是无问题的。即使它有点慢,这与正确的方法相比毫无意义 - 即将对象视为对象。
作为 1M 对象的一些指标:
struct/field: 50ms
class/property: 229ms
基于以下内容(速度差异在对象分配中,而不是字段与属性)。因此大约慢了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();
}
}
答案 1 :(得分:0)
我只能猜测为什么它们只支持属性:也许是因为它似乎是.NET框架中的一个普遍约定,永远不会公开可变字段(probably to safeguard binary compatibility),并且它们不知何故预计所有程序员都遵循相同的约定。
此外,尽管使用相同的语法访问字段和属性,但数据绑定使用反射,并且(因此我听说)反射必须以不同方式用于访问字段而不是访问属性。