2011-11-03 3 views
6

오늘 부울 [,] DataMember가 포함 된 DataContract를 serialize/deserialize하는 중 예기치 않은 문제가 발생했습니다. csc도 런타임도이 정의에 반대하지 않았습니다. 그러나 deserialized 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가 그다지 강력하지 않은 전화 응용 프로그램입니다). 직렬화는 앱이 비활성화되거나 닫힐 때만 발생합니다 (드물게). – 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] 

EDIT된다 :에 했나요로서 주석을 사용하면 유용한 경계 검사를 잃게됩니다. 문제가 있다면 다시 추가 할 수 있습니다.

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

참고 : x가 유효한 경우 y 사례는 이미 배열에 의해 처리됩니다.

+0

사실,하지만 범위 검사의 일부 요소를 잃게됩니다 ('3x4' 배열의 경우, (6,1)의 인덱스를 지정할 수 있으며, 여전히 전체 배열 내의 위치를 ​​계산합니다) –

+0

맞아요. , 이러한 수표는 수작업으로 수행해야합니다. 업데이트 중. – jv42

관련 문제