2011-11-03 37 views
6

我今天遇到了意想不到的问题,试图序列化/反序列化包含bool [,] DataMember的DataContract。 csc和运行时都不会反对这个定义,但是反序列化的bool [,] DataMember中的值是不正确的。在阅读this thread后,我最初的反应是将有问题的属性转换为锯齿状数组。不过,由于this article通知锯齿阵列在对角或随机访问时(正好是我的用例)表现糟糕,所以我不得不放弃这种方法。因此,我最终编写了上述msdn线程中提出的解决方案的策划版本(将矩形转换为锯齿形,并且在导出/导入时将其转换为反正方形,请参阅下面的代码摘录),并且工作正常。DataContractSerializer不支持矩形阵列

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

我想知道如果有一个更简洁的解决方案,或这种或另一种方法。

+2

“锯齿状阵列表现得很糟糕” - 但与I/O,转换和序列化相比,这确实很重要吗? –

+1

持久性格式和运行时格式不必相同 –

+1

在应用程序的核心,所讨论的数组被访问数百万次(并且它是一个电话应用程序,其中CPU不那么强大)。序列化仅在App停用或关闭时发生(不频繁)。 – javvin

回答

0

而不是实现GetDeserializedObject & GetObjectToSerialize,我会公开一个不同的对象进行序列化。单维数组就足够了。为什么你需要摆在首位多维数组

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

是否有一个原因: 我会做到这一点?

如果您使用的是一维数组,你只需要计算适当的指数,一个非常简单的计算:

array[x, y] 

成为

array[(y * width) + x] 

编辑:作为mentionned评论,你会失去一些有用的边界检查。如果这是一个问题,你可以重新添加他们:

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

注:在Y的情况下会被阵列已经抛出,如果x是有效的。

+0

没错,但是你失去了一些边界检查的元素(对于一个'3x4'数组,你可以指定一个'(6,1)'的索引,并且它仍然会计算整个数组中的一个位置) –

+0

你是对的,这些检查需要手工完成。更新。 – jv42