XmlSerializer - 型を反映するエラーが発生しました
-
09-06-2019 - |
質問
C# .NET 2.0 を使用して、次のような複合データ クラスを作成しました。 [Serializable]
その上の属性。を作成しています XMLSerializer
クラスを作成し、それをコンストラクターに渡します。
XmlSerializer serializer = new XmlSerializer(typeof(DataClass));
次のような例外が発生します。
タイプを反映するエラーが発生しました。
データ クラス内には別の複合オブジェクトがあります。これにも必要がありますか? [Serializable]
属性を使用するか、それを最上位のオブジェクトに設定することによって、内部のすべてのオブジェクトに再帰的に適用されますか?
解決
取得している内部例外を見てください。どのフィールド/プロパティでシリアル化に問題があるのかがわかります。
フィールド/プロパティを XML シリアル化から除外するには、フィールド/プロパティを [XmlIgnore]
属性。
そうは思わない XmlSerializer
を使用します [Serializable]
属性なので、それが問題ではないと思います。
他のヒント
シリアル化されたクラスにはデフォルトが必要であることに注意してください(つまり、パラメーターなし) コンストラクター。コンストラクターがまったくない場合でも問題ありません。ただし、パラメーターを含むコンストラクターがある場合は、デフォルトのコンストラクターも追加する必要があります。
私も同様の問題を抱えていましたが、同じ名前を持つ 2 つのクラス (1 つはもう 1 つのサブクラス) をシリアライザーが区別できないことがわかりました。内部例外は次のようになります。
'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
はブラックボックスです。シリアル化プロセスをさらにデバッグする場合は、これらのリンクを確認してください。
特定の属性を処理する必要がある場合 (つまり、ディクショナリ、または任意のクラス) を実装できます。 IXmlSerialable より自由度を高めるインターフェース より冗長なコーディングが必要になります.
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
リフレクションを使用したクラス。
.Net 2.0 の Dictionary クラスは XML を使用してシリアル化できないが、バイナリ シリアル化を使用すると適切にシリアル化できることがわかりました。
回避策を見つけました ここ.
最近、新しいプロパティを追加するときに、Web 参照の部分クラスでこれを取得しました。自動生成されたクラスには次の属性が追加されていました。
[System.Xml.Serialization.XmlElementAttribute(Order = XX)]
自動生成されたシーケンスの最後よりも 1 つ高い順序で同様の属性を追加する必要がありましたが、これで問題は解決しました。
私も Serializable 属性がオブジェクトになければならないと考えていましたが、私が完全な初心者でない限り (深夜のコーディング セッションの真っ最中です)、次の方法で機能します。 スニペットコンパイラ:
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 がパブリック プロパティに対するリフレクションを使用していると想像します。
同じエラーが発生し、次のタイプのプロパティがあることを発見しました IEnumerable<SomeClass>
が問題でした。どうやら IEnumerable
直接シリアル化することはできません。
代わりに、次を使用できます。 List<SomeClass>
.
連続する 2 つの要素の順序が同じになる状況がありました
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "SeriousInjuryFlag")]
....何らかのコード...
[System.Xml.Serialization.XmlElementAttribute(IsNullable = true, Order = 0, ElementName = "AccidentFlag")]
クラス内の新しいプロパティごとに順序を 1 ずつ増やすようにコードを変更したところ、エラーは解消されました。
また、ユーザー インターフェイス コントロールはシリアル化できないこと、およびクリップボードに渡すオブジェクトはシリアル化可能である必要があり、そうでないと他のプロセスに渡すことができないことにも注意してください。
私はこれまで使用してきました NetDataSerialiser
ドメインクラスをシリアル化するクラス。 NetDataContractSerializer クラス.
ドメイン クラスはクライアントとサーバー間で共有されます。
[System.Xml.Serialization.XmlElementAttribute("strFieldName", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
//または
xmlignore] string [] strfielsname {get; set;}
同じ問題が発生し、私の場合、オブジェクトには ReadOnlyCollection がありました。コレクションをシリアル化できるようにするには、Add メソッドを実装する必要があります。