2011-11-03 11 views
6

Hoy me encontré con un problema inesperado al tratar de serializar/deserializar un DataContract que contiene un bool [,] DataMember. Ni el csc ni el tiempo de ejecución objetaban esta definición, sin embargo, los valores en el booleador deserializado [,] DataMember simplemente no eran correctos. Después de leer this thread, mi reacción inicial fue convertir la propiedad problemática en una matriz dentada. Tuve que abandonar ese enfoque pronto, sin embargo, desde this article informa que las matrices irregulares funcionan miserablemente cuando se accede en diagonal o aleatoriamente (exactamente mi caso de uso). Así que terminé escribiendo una versión curada de la solución propuesta en el hilo msdn anterior (convertir rectangular a irregular y viceversa al exportar/importar, ver fragmentos de código a continuación) y que funciona bien.DataContractSerializer no admite matrices rectangulares

public object GetDeserializedObject(object obj, Type targetType) 
{ 
    if (obj is GridArrayWrapper) 
    { 
     bool[,] arr; 
     GridArrayWrapper wrapper = (GridArrayWrapper)obj; 
     if (wrapper.Array == null) return null; 
     int d0 = wrapper.Array.Length; 
     if (d0 == 0) 
     { 
      return new bool[0, 0]; 
     } 
     var d1 = wrapper.Array[0].Length; 
     arr = new bool[d0, d1]; 
     for (int i = 0; i < d0; i++) 
     { 
      if (wrapper.Array[i].Length != d1) throw new ArgumentException("Not a rectangular array"); 
      for (var j = 0; j < d1; j++) 
      { 
       arr[i, j] = wrapper.Array[i][j]; 
      } 
     } 
     return arr; 
    } 
    return obj; 
} 

public object GetObjectToSerialize(object obj, Type targetType) 
{ 
    if (obj is bool[,]) 
    { 
     bool[,] arr = (bool[,])obj; 
     GridArrayWrapper wrapper = new GridArrayWrapper(); 
     int d0 = arr.GetLength(0); 
     int d1 = arr.GetLength(1); 
     wrapper.Array = new bool[d0][]; 
     for (int i = 0; i < wrapper.Array.Length; i++) 
     { 
      wrapper.Array[i] = new bool[d1]; 
      for (int j = 0; j < d1; j++) 
      { 
       wrapper.Array[i][j] = arr[i, j]; 
      } 
     } 
     return wrapper; 
    } 
    return obj; 
} 

Me pregunto, sin embargo, si hay una solución más concisa a este u otro enfoque.

+2

"que las matrices dentadas funcionan de manera miserable", pero ¿eso realmente importa en comparación con la E/S, la conversión y la serialización? –

+1

El formato de persistencia y el formato de tiempo de ejecución no tienen que ser los mismos –

+1

En el núcleo de la aplicación, la matriz en cuestión se accede millones de veces (y es una aplicación de teléfono donde las CPU no son tan potentes). La serialización solo tiene lugar cuando la aplicación se desactiva o se cierra (poco frecuente). – javvin

Respuesta

0

En lugar de implementar GetDeserializedObject & GetObjectToSerialize, exponer un objeto diferente para la serialización. Una matriz dimensional única sería suficiente por cierto. Me gustaría hacer esto:

//No Datamember here 
public bool[,] Data; 

[DataMember(Name="Data")] 
public bool[] XmlData 
{ 
    get { 
    bool[] tmp = new bool[Data.GetLength(0) * Data.GetLength(1)]; 
    Buffer.BlockCopy(Data, 0, tmp, 0, tmp.Length * sizeof(bool)); 
    return tmp; 
    } 
    set { 
    bool[,] tmp = new bool[,]; 
    Buffer.BlockCopy(value, 0, tmp, 0, value.Length * sizeof(bool)); 
    this.Data = tmp; 
    } 
} 
0

¿Existe una razón por qué necesita una matriz multidimensional en el primer lugar?

Si utiliza una sola matriz dimensión, sólo hay que calcular el índice adecuado, con un cálculo muy simple:

array[x, y] 

convierte

array[(y * width) + x] 

EDIT: Como lo mencionan en comentarios, luego perderá algunos límites de comprobación útiles. Si eso es un problema, se puede volver a añadirlos:

if (x < 0 || x > width || y < 0 || y > height) 
    throw new IndexOutOfRangeException(); 

Nota: los casos serían Y ya lanzados por la matriz si x es válida.

+0

Cierto, pero pierde algunos elementos de comprobación de límites (para una matriz '3x4', puede especificar un índice de' (6,1) ', y eso aún calculará una posición dentro de la matriz general) –

+0

Tiene razón , estas verificaciones deben hacerse a mano. Actualizando – jv42

Cuestiones relacionadas