Pregunta

Tenemos una gran cantidad de objetos de valor inmutable en nuestro modelo de dominio, un ejemplo de esto es una posición, definida por una latitud, longitud y altura.

/// <remarks>When I grow up I want to be an F# record.</remarks>
public class Position
{
    public double Latitude
    {
        get;
        private set;
    }

    // snip

    public Position(double latitude, double longitude, double height)
    {
        Latitude = latitude;
        // snip
    }
}

La manera obvia de permitir la edición de una posición es construir un modelo de vista que tiene getters y organismos, así como un método toPosition () para extraer la instancia posición inmutable validado. Si bien esta solución no estaría mal, que daría lugar a una gran cantidad de código duplicado, especialmente XAML.

Los objetos de valor en cuestión consisten en entre tres y cinco propiedades que son por lo general alguna variante de X, Y, Z y un poco de materia auxiliar. Dado esto, había considerado la creación de tres ViewModels para manejar las diversas posibilidades, donde cada ViewModel necesitaría para mostrar las propiedades para el valor de cada propiedad, así como una descripción para mostrar para cada etiqueta (por ejemplo "Latitud").

Yendo más lejos, parece como si pudiera simplificarlo a un modelo de vista general que se puede tratar con N propiedades y conectar todo lo que hasta el uso de la reflexión. Algo así como una cuadrícula de propiedades, pero para objetos inmutables. Un problema con una cuadrícula de propiedad es que quiero ser capaz de cambiar el aspecto para que pueda tener etiquetas y cuadros de texto, tales como:

Latitude:   [      32 ]  <- TextBox
Longitude:  [     115 ]
Height:     [      12 ]

o ponerlo en una cuadrícula de datos como por ejemplo:

Latitude  |  Longitude  |  Height
      32           115         12

Así que mi pregunta es:

¿Se puede pensar en una manera elegante de resolver este problema? ¿Hay bibliotecas que hacen esto o artículos acerca de algo similar?

Estoy buscando principalmente:

  • duplicación de código a ser minimizado
  • Fácil de añadir nuevos tipos de objetos de valor
  • posible extender con algún tipo de validación
¿Fue útil?

Solución

He encontrado esta vieja cuestión, mientras que la investigación de mis posibles opciones en la misma situación. Pensé que debería actualizarlo en caso de que alguien se tropieza demás a ella:

Otra opción (no disponible cuando Pablo ofreció su solución, ya .Net 4 no estaba aún) es usar la misma estrategia, pero en lugar de implementar usando CustomTypeDescriptors, utilice una combinación de medicamentos genéricos, objetos dinámicos y la reflexión para lograr el mismo efecto.

En este caso, se define una clase

class Mutable<ImmutableType> : DynamicObject
{
   //...
}

Es constructor toma una instancia del tipo inmutable y un delegado que construye una nueva instancia de la misma fuera de un diccionario, al igual que en la respuesta de Pablo. La diferencia aquí, sin embargo, es que se ha sobrepasado la TryGetMember y TrySetMember para poblar un diccionario interno que está finalmente va a utilizar como argumento para el constructor-delegado. Se utiliza la reflexión con el fin de verificar que las únicas propiedades que se va a aceptar son los que realmente se implementan en ImmutableType.

En cuanto al rendimiento, apuesto a que la respuesta de Pablo es más rápido, y no implica objetos dinámicos, que son conocidos para poner desarrolladores de C # en un ataque. Sin embargo, la implementación de esta solución también es un poco más simple, porque descriptores de tipo son un poco arcano.


Esta es la solicitada / ejemplo de implementación de prueba de concepto:

https://bitbucket.org/jwrush/mutable-generic-example

Otros consejos

Los descriptores de tipo personalizado se podrían utilizar para resolver este problema. Antes de unirse a una posición, su descriptor de tipo podría arrancar, y proporcionar métodos get y set para construir temporalmente los valores. Cuando se cometen los cambios, se podría construir el objeto inmutable.

Podría ser algo como esto:

DataContext = new Mutable(position, 
    dictionary => new Position(dictionary["lattitude"], ...)
);

Sus fijaciones todavía puede tener este aspecto:

<TextBox Text="{Binding Path=Lattitude}" />

Debido a que el objeto mutable será 'fingir' que tienen propiedades como LAttitude gracias a su TypeDescriptor.

Como alternativa puede utilizar un convertidor en sus fijaciones y llegar a algún tipo de convención.

Su clase mutable tomaría el objeto inmutable actual, y una Func<IDictionary, object> que le permite crear el nuevo objeto inmutable una vez que se completa la edición. Su clase mutable haría uso del descriptor de tipos, lo que crearía PropertyDescriptors que crean el nuevo objeto inmutable en su constitución.

Para un ejemplo de cómo utilizar descriptores de tipo, ver aquí:

http://www.paulstovell.com/editable-object-adapter

Editar : si desea limitar la frecuencia se crean los objetos inmutables, también se podría hacer en BindingGroups y IEditableObject, que su mutable también se puede poner en práctica.

  

¿Se puede pensar en una manera elegante de resolver este problema?

Sinceramente, sólo bailan alrededor del problema, pero no menciona el problema en sí;).

Si yo supongo correctamente su problema, entonces la combinación de MultiBinding y IMultiValueConverter debe hacer el truco.

HTH.

P.S. Por cierto, usted tiene instancias de clases inmutables, no objetos de valor. Con los objetos de valor (que se describe por struct palabra clave) que bailarías mucho más, no importa si hubo o no definidores:)

.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top