9

XML にシリアライズしようとしているオブジェクトがあります。このオブジェクトの内部には、ジェネリック型 (抽象クラス) のリストがあります。このリストの各項目は異なるクラスである可能性がありますが、すべてが抽象基本クラスから継承されています。

public abstract class animal
{
  public string type { get; set; }
}
public class cat:animal
{
  public string size { get; set; }
  public string furColor { get; set; }
}
public class fish:animal
{
  public string size { get; set; }
  public string scaleColor { get; set; }
}

リストをシリアル化すると、次のようになります。

<animal type="cat">
  <size>medium</size>
  <furColor>black</furColor>
</animal>
<animal type="fish">
  <size>small</size>
  <scaleColor>silver</scaleColor>
</animal>

私は簡単な解決策を試しました:

[XmlElement("Animal")]
public List<animal> Animals { get; set; }

しかし、オブジェクト タイプ「cat」が想定されていないため、エラーがスローされます。[XmlInclude] タグを基本クラス、派生クラス、またはそれを含むクラス全体 (zoo と呼びましょう) のいずれかに追加しても、これは役に立ちません。

単一のクラスに typeof 指定を使用できます。

[XmlElement("Animal", typeof(cat))]
public List<animal> Animals { get; set; }

猫だけを使用している限り、これは私が望むように適切に機能します。繰り返しますが、ミックスに魚を追加すると、同じエラーで爆発します (魚を期待していません)。

複数の typeof 属性を追加できます。

[XmlElement("Animal")]
[XmlElementAttribute(typeof(cat))]
[XmlElementAttribute(typeof(fish))]
public List<animal> Animals { get; set; }

これはコンパイルされますが、要素名を無視し、オブジェクトをそれぞれ<cat> </cat>およびとしてシリアル化します<fish> </fish>が、これは受け入れられません。

複数の [XmlElement] タグを追加してみました:

[XmlElement("Animal", typeof(cat))]
[XmlElement("Animal", typeof(fish))]
public List<animal> Animals { get; set; }

これは別の例外をスローします。今回は、オブジェクト「cat」と「fish」の両方が同じスコープでタイプ「Animal」を使用します。

誰でもこれを回避する方法を考えることができますか?

UPDATEもう少し掘り下げた後、名前空間を基本クラスに追加することを提案するこのSO投稿を見つけました:

[XmlRoot(Namespace="myNamespace")]
[XmlInclude(typeof(cat))]
[XmlInclude(typeof(fish))]
public abstract class animal

これをシリアル化すると、次のようになります。

<animal xsi:type="cat" type="cat">
  ...
</animal>
<animal xsi:type="fish" type="fish">
  ...
</animal>

ここで、xsi:type="cat"はクラスの名前を指し、type="cat"は基本クラス内で作成されたタイプ属性を指します (一番上の例を参照)。これは私が必要とするものに非常に近いものであり、ここで経験不足に苦しんでいるだけかもしれませんが、xsi:type 属性のリストを取り除く方法はありますか?

4

3 に答える 3

4

XmlInclude 属性を基本クラスに追加すると、このシリアル化の問題が解決するはずです

    [Serializable]
    [XmlInclude(typeof(cat))]
    [XmlInclude(typeof(fish))]
    class animals
    {
         ....
    }

    public class cat:animals
    {
      public string size { get; set; }
      public string furColor { get; set; }
    }

    public class fish:animals
    {
      public string size { get; set; }
      public string scaleColor { get; set; }
    }

アップデート

これは私の側で機能する簡単な例です。 typeof() メソッドで取得できるため、実際には type 属性は必要ありません。type 属性に別の目的がない限り。

        List<animal> animals = new List<animal>();
        cat catofdoom = new cat();
        catofdoom.furColor = "brown";
        catofdoom.size = "10 pounds";
        animals.Add(catofdoom);

        fish fishofdoom = new fish();
        fishofdoom.scaleColor = "blue";
        fishofdoom.size = "12 inches";
        animals.Add(fishofdoom);


        try
        {
            XmlSerializer xs = new XmlSerializer(typeof(List<animal>));
            using (StreamWriter wr = new StreamWriter("animal.xml"))
            {
                xs.Serialize(wr, animals);
            }
        }
        catch (Exception e)
        {

            throw;
        }

結果は次のようになります (オプションのない非常に基本的なシリアル化):

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfAnimal xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <animal xsi:type="cat">
    <size>10 pounds</size>
    <furColor>brown</furColor>
  </animal>
  <animal xsi:type="fish">
    <size>12 inches</size>
    <scaleColor>blue</scaleColor>
  </animal>
</ArrayOfAnimal>
于 2013-02-13T23:19:14.060 に答える
2

両方必要です!

[Serializable]
[XmlInclude(typeof(cat))]
[XmlInclude(typeof(fish))]
class animals
{
     ....
}

public class cat:animals
{
  public string size { get; set; }
  public string furColor { get; set; }
}

public class fish:animals
{
  public string size { get; set; }
  public string scaleColor { get; set; }
}

名前のわずかな変更に注意してくださいXmlElement。これで正しく動作します。

[XmlElement("cat", typeof(cat))]
[XmlElement("fish", typeof(fish))]
public List<animal> Animals { get; set; }
于 2014-09-30T14:10:30.263 に答える
1

DataContractSerializerを使用し、既知のタイプをシリアライザーに含めることをお勧めします。XmlIncludeを使用することは、カプセル化の原則を破るようなものです。いくつかのサンプルについては、提供されているMSDNリンクを参照してください...

于 2013-02-14T14:23:39.947 に答える