2009-05-09 11 views
16

Tengo un servicio de WCF que pasa alrededor de las actualizaciones de estado a través de una estructura de este modo:¿Por qué WPF admite el enlace a las propiedades de un objeto, pero no a los campos?

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

expongo una propiedad en un modelo de vista así:

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

Y XAML así:

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

Cuando ejecuto la aplicación, veo errores en la ventana de salida que indican que no se puede encontrar la propiedad Total. Revisé y comprobé dos veces y lo escribí correctamente. Se me ocurrió que los errores indican específicamente que no se puede encontrar la "propiedad". Entonces agregar una propiedad a la estructura lo hizo funcionar bien. Pero me parece extraño que WPF no pueda manejar el enlace unidireccional a los campos. Sintácticamente accede a ellos de la misma manera en el código y parece tonto tener que crear un modelo de vista personalizado solo para la estructura de StatusInfo. ¿Me he perdido algo sobre el enlace de WPF? ¿Se puede vincular a un campo o la propiedad es vinculante de la única manera?

Respuesta

21

Encuadernación generalmente no funciona en los campos. La mayoría de los enlaces se basan, en parte, en el modelo ComponentModel PropertyDescriptor, que (de forma predeterminada) funciona en las propiedades. Esto permite notificaciones, validación, etc. (ninguno de los cuales funciona con campos).

Por más razones que las que yo puedo mencionar, los campos públicos son una mala idea. Deben ser propiedades, hecho. Del mismo modo, las estructuras mutables son una mala idea muy. No menos importante, protege contra la pérdida inesperada de datos (comúnmente asociada con estructuras mutables). Esta debería ser una clase:

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

Ahora se comportará como usted cree que debería. Si usted quiere que sea un inmutable estructura, que estaría bien (pero los datos de unión habría un solo sentido, por supuesto):

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

Sin embargo, lo haría primera pregunta de por qué esto es una estructura en primer lugar. Es muy raro para escribir una estructura en lenguajes .NET. Tenga en cuenta que la capa de proxy "mex" de WCF lo creará como una clase para el consumidor de todos modos (a menos que use el ensamblaje compartido).


En respuesta a la respuesta "¿Por qué utilizar estructuras" ("desconocido (Google)"):

Si esto es una respuesta a mi pregunta, es un error de muchas maneras. En primer lugar, los tipos de valor como variables se asignan comúnmente (primero) en la pila. Si se insertan en el montón (por ejemplo, en una matriz/lista), no hay mucha diferencia en la sobrecarga de una clase, un pequeño encabezado de objeto más una referencia. Las estructuras siempre deben ser small. Algo con múltiples campos será sobredimensionado, y matará a su pila o simplemente causará lentitud debido al blitting. Además, las estructuras deben ser inmutables, a menos que usted realmente sepa lo que está haciendo.

Casi cualquier cosa que represente un objeto debe ser inamovible.

Si está accediendo a una base de datos, la velocidad de la estructura frente a la clase no es un problema en comparación con salir fuera de proceso y probablemente a través de la red.Incluso si es un poco más lento, eso no significa nada en comparación con el punto de hacerlo bien, es decir, tratar los objetos como objetos.

Como algunas métricas más de 1M objetos:

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

basa en los siguientes (la diferencia de velocidad es en la asignación de objeto, no campo contra la propiedad). Entonces, aproximadamente 5 veces más lento, pero todavía muy, muy rápido. Dado que este no será su cuello de botella, ¡no optimice esto prematuramente!

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

Como programador de C++ encuentro que sus comentarios anteriores son muy difíciles de comprender. También parece llegar a conclusiones diferentes. Por ejemplo, dices: "Entonces, aproximadamente 5 veces más lento, pero aún así, muy rápido". Mientras que lo veo como, "El uso de estructuras es aproximadamente 5 veces más rápido, pero aún muy, muy lento". –

+7

@Daniel suspiro, aquí vamos de nuevo, "C++ es más rápido que todo, nunca, y debe usarse en todo momento" (suspiro). En una amplia variedad de aplicaciones, no existe una diferencia apreciable, aparte de que una sea significativamente más fácil de hacer bien. –

+0

¡Nunca dije que C++ fuera más rápido! Concluir esto indicó que tiene algunas ideas preconcebidas serias (o quizás ideas erróneas). "En una amplia variedad de aplicaciones no existe una diferencia apreciable, aparte de que sea significativamente más fácil hacerlo bien", así que estamos de acuerdo, aunque C++ puede ser más rápido, esto no es importante, sin embargo, C++ hace que sea más fácil hacerlo bien y esto es significativo O tal vez solo malinterpreté lo que dijiste para apoyar mi argumento ... De hecho, suspiro. –

0

sólo puedo adivinar por qué sólo admiten propiedades: tal vez porque parece ser una convención universal en el marco .NET no volver a exponer los campos mutables (probably to safeguard binary compatibility), y que de alguna manera se espera que todos los programadores que siguen el mismo convención.

Además, aunque se accede a los campos y propiedades con la misma sintaxis, el enlace de datos utiliza la reflexión y (por lo que he oído) la reflexión debe usarse de forma diferente para acceder a los campos que para acceder a las propiedades.

Cuestiones relacionadas