回答:
あなたが得ている内側の例外を見てください。シリアル化で問題が発生しているフィールド/プロパティがわかります。
[XmlIgnore]
属性で装飾することにより、フィールド/プロパティをxmlシリアル化から除外できます。
XmlSerializer
[Serializable]
属性を使用しないので、それが問題だとは思いません。
IList
、それが必要であるときのように、私の「直列化される」クラスにプロパティがあることでしたList
。
シリアル化されたクラスには、デフォルト(つまり、パラメーターなし)コンストラクターが必要であることに注意してください。コンストラクタがない場合でも問題ありません。ただし、パラメーター付きのコンストラクターがある場合は、デフォルトのコンストラクターも追加する必要があります。
同様の問題があり、シリアライザが同じ名前の2つのクラスを区別できないことがわかりました(一方は他方のサブクラスでした)。内部例外は次のようになります。
'Types BaseNamespace.Class1'および 'BaseNamespace.SubNamespace.Class1'は両方とも、ネームスペース ''からのXMLタイプ名 'Class1'を使用します。XML属性を使用して、型の一意のXML名または名前空間、あるいはその両方を指定します。
ここで、BaseNamespace.SubNamespace.Class1は、BaseNamespace.Class1のサブクラスです。
私がする必要があるのは、クラスの1つに属性を追加することです(基本クラスに追加しました)。
[XmlType("BaseNamespace.Class1")]
注:クラスのレイヤーが複数ある場合は、それらにも属性を追加する必要があります。
また、XmlSerializer
抽象プロパティをシリアル化できないことにも注意してください。ここで(ソリューションコードを追加した)私の質問を参照してください。
私による最も一般的な理由:
- the object being serialized has no parameterless constructor
- the object contains Dictionary
- the object has some public Interface members
シリアル化グラフのすべてのオブジェクトは、シリアル化可能である必要があります。
XMLSerializer
はブラックボックスなので、シリアライゼーションプロセスをさらにデバッグする場合は、これらのリンクを確認してください。
特定の属性(つまり、ディクショナリ、または任意のクラス)を処理する必要がある場合は、IXmlSerialiableインターフェイスを実装できます。これにより、より冗長なコーディングを犠牲にして、より自由になります。
public class NetService : IXmlSerializable
{
#region Data
public string Identifier = String.Empty;
public string Name = String.Empty;
public IPAddress Address = IPAddress.None;
public int Port = 7777;
#endregion
#region IXmlSerializable Implementation
public XmlSchema GetSchema() { return (null); }
public void ReadXml(XmlReader reader)
{
// Attributes
Identifier = reader[XML_IDENTIFIER];
if (Int32.TryParse(reader[XML_NETWORK_PORT], out Port) == false)
throw new XmlException("unable to parse the element " + typeof(NetService).Name + " (badly formatted parameter " + XML_NETWORK_PORT);
if (IPAddress.TryParse(reader[XML_NETWORK_ADDR], out Address) == false)
throw new XmlException("unable to parse the element " + typeof(NetService).Name + " (badly formatted parameter " + XML_NETWORK_ADDR);
}
public void WriteXml(XmlWriter writer)
{
// Attributes
writer.WriteAttributeString(XML_IDENTIFIER, Identifier);
writer.WriteAttributeString(XML_NETWORK_ADDR, Address.ToString());
writer.WriteAttributeString(XML_NETWORK_PORT, Port.ToString());
}
private const string XML_IDENTIFIER = "Id";
private const string XML_NETWORK_ADDR = "Address";
private const string XML_NETWORK_PORT = "Port";
#endregion
}
XmlSerializerを「拡張」する洗練された方法を実装するエレガントな方法を示す興味深い記事があります。
記事は言う:
IXmlSerializableは公式ドキュメントでカバーされていますが、ドキュメントはそれが公的な使用を目的としていないことを述べており、それ以上の情報を提供していません。これは、開発チームがこの拡張機能フックを修正、無効化、または完全に削除する権利を留保したかったことを示しています。ただし、この不確実性を受け入れて将来起こり得る変化に対処する用意がある限り、それを利用できない理由はありません。
これは、IXmlSerializable
あまりにも複雑な実装を避けるために、独自のクラスを実装することをお勧めします。
... XmlSerializer
リフレクションを使用してカスタムクラスを実装するのは簡単です。
Serializable属性はオブジェクト上にある必要があると私も思いましたが、私が完全な初心者でない限り(私は深夜のコーディングセッションの真っ最中です)、SnippetCompilerからの次の作業を行います。
using System;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using System.Xml.Serialization;
public class Inner
{
private string _AnotherStringProperty;
public string AnotherStringProperty
{
get { return _AnotherStringProperty; }
set { _AnotherStringProperty = value; }
}
}
public class DataClass
{
private string _StringProperty;
public string StringProperty
{
get { return _StringProperty; }
set{ _StringProperty = value; }
}
private Inner _InnerObject;
public Inner InnerObject
{
get { return _InnerObject; }
set { _InnerObject = value; }
}
}
public class MyClass
{
public static void Main()
{
try
{
XmlSerializer serializer = new XmlSerializer(typeof(DataClass));
TextWriter writer = new StreamWriter(@"c:\tmp\dataClass.xml");
DataClass clazz = new DataClass();
Inner inner = new Inner();
inner.AnotherStringProperty = "Foo2";
clazz.InnerObject = inner;
clazz.StringProperty = "foo";
serializer.Serialize(writer, clazz);
}
finally
{
Console.Write("Press any key to continue...");
Console.ReadKey();
}
}
}
XmlSerializerがパブリックプロパティに対してリフレクションを使用していると思います。
2つの要素の順序が同じである状況がありました
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "SeriousInjuryFlag")]
....いくつかのコード...
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "AccidentFlag")]
コードを変更して、クラスの新しいプロパティごとに1つずつ順序を増やすと、エラーは解消しました。
NetDataSerialiser
クラスを使用してドメインクラスをシリアル化しています。NetDataContractSerializerクラス。
ドメインクラスはクライアントとサーバー間で共有されます。
同じ問題があり、私の場合、オブジェクトにはReadOnlyCollectionがありました。コレクションがシリアル化可能になるには、Addメソッドを実装する必要があります。
私はこれまでにここで説明したすべてに対して少し異なる解決策を持っているので、将来の文明のためにここにあります!
元の型がaだったので、「time」のデータ型を宣言し、TimeSpan
その後に変更しましたString
:
[System.Xml.Serialization.XmlElementAttribute(DataType="time", Order=3)]
しかし、実際のタイプは文字列でした
public string TimeProperty {
get {
return this.timePropertyField;
}
set {
this.timePropertyField = value;
this.RaisePropertyChanged("TimeProperty");
}
}
DateType
プロパティを削除することにより、Xml
シリアル化できます
[System.Xml.Serialization.XmlElementAttribute(Order=3)]
public string TimeProperty {
get {
return this.timePropertyField;
}
set {
this.timePropertyField = value;
this.RaisePropertyChanged("TimeProperty");
}
}