2011-11-03 12 views
6

Ho avuto un problema inatteso oggi, tentando di serializzare/deserializzare un DataContract contenente un membro [,] DataMember. Né csc né runtime hanno contestato questa definizione, tuttavia i valori nel boer deserializzato [,] DataMember non erano corretti. Dopo aver letto this thread, la mia reazione iniziale è stata quella di convertire la proprietà problematica in una matrice seghettata. Presto però ho dovuto abbandonare questo approccio poiché lo this article informa che gli array frastagliati funzionano miseramente quando si accede in diagonale o in modo casuale (esattamente il mio caso d'uso). Così ho finito per scrivere una versione curata della soluzione proposta nel precedente thread msdn (convertire rettangolare in jagged e viceversa dopo l'esportazione/importazione, vedere gli estratti di codice sotto) e questo funziona bene.DataContractSerializer che non supporta matrici rettangolari

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

Mi chiedo tuttavia se c'è una soluzione più concisa a questo o un altro approccio.

+2

"gli array frastagliati si comportano in modo miserabile", ma ciò conta davvero rispetto all'I/O, alla conversione e alla serializzazione? –

+1

Il formato di persistenza e il formato di runtime non devono essere gli stessi –

+1

Al centro dell'applicazione si accede l'array in questione milioni di volte (ed è un'app per telefono in cui le CPU non sono così potenti). La serializzazione avviene solo quando l'app si disattiva o si chiude (poco frequente). – javvin

risposta

0

Invece di implementare GetDeserializedObject & GetObjectToSerialize, vorrei esporre un oggetto diverso per la serializzazione. A proposito, una matrice monodimensionale sarebbe sufficiente. farei questo:

//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

C'è un motivo per cui è necessario un array multidimensionale, in primo luogo?

Se si usa un array monodimensionale, è sufficiente per calcolare l'indice corretto, con un semplice calcolo:

array[x, y] 

diventa

array[(y * width) + x] 

EDIT: Come citato in commenti, perderai quindi qualche utile controllo dei limiti. Se questo è un problema, si potrebbe ri-aggiungere:

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

Nota: i casi y sarebbero già gettati dalla matrice se la x è valido.

+0

Vero, ma si perdono alcuni elementi di controllo dei limiti (per un array '3x4', è possibile specificare un indice di' (6,1) ', e questo calcolerà ancora una posizione all'interno dell'array complessivo) –

+0

Hai ragione , questi controlli devono essere fatti a mano. In aggiornamento. – jv42

Problemi correlati