2011-11-03 10 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がそれほど強力でない電話アプリです)。シリアライゼーションは、アプリケーションの非アクティブ化またはクローズ時(まれに)にのみ発生します。 – javvin

答えて

0

GetDeserializedObject & GetObjectToSerializeを実装する代わりに、私はシリアル化のために別のオブジェクトを公開します。ところで、1次元配列で十分です。

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

は、あなたが最初の場所で多次元配列を必要とする理由があります: は、私はこれを行うだろうか?

あなたは1次元配列を使用する場合は、あなただけの非常に簡単な計算で、適切な指標を計算する必要がありますにmentionnedとして:

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

関連する問題