XmlSerializer
単純なオブジェクトをシリアル化してから逆シリアル化するために使用しています。驚いたことにオブジェクトを逆シリアル化すると、子オブジェクトが適切に逆シリアル化されておらず、代わりにになっていることがわかりましたXmlNode[]
。
これが私が持っている構造に非常に近いものです:
// This line I put in here as a way of sneaking into the XML the
// root node's C# namespace, since it's not the same as the
// deserializing code and the deserializing code seemed unable to
// deserialize properly without knowing the Type (see my code below).
// So I basically just use this fake construct to get the namespace
// and make a Type of it to feed the XmlSerializer() instantiation.
[XmlRoot(Namespace = "http://foo.com/CSharpNamespace/Foo.Bar")]
// This is because QueuedFile can be given to the Argument array.
[XmlInclude(typeof(QueuedFile))]
// This class is Foo.Bar.CommandAndArguments
public class CommandAndArguments {
public String Command;
public object[] Arguments;
}
// I don't think this matters to XmlSerialize, but just in case...
[Serializable()]
// I added this line just thinking maybe it would help, but it doesn't
// do anything. I tried it without the XmlType first, and that
// didn't work.
[XmlType("Foo.Baz.Bat.QueuedFile")]
// This class is Foo.Baz.Bat.QueuedFile (in a different c#
// namespace than CommandAndArguments and the deserializing code)
public QueuedFile {
public String FileName;
public String DirectoryName;
}
そして、それを逆シリアル化するコードは次のようになります。
public static object DeserializeXml(String objectToDeserialize)
{
String rootNodeName = "";
String rootNodeNamespace = "";
using (XmlReader xmlReader = XmlReader.Create(new StringReader(objectToDeserialize)))
{
if (xmlReader.MoveToContent() == XmlNodeType.Element)
{
rootNodeName = xmlReader.Name;
rootNodeNamespace = xmlReader.NamespaceURI;
if (rootNodeNamespace.StartsWith("http://foo.com/CSharpNamespace/"))
{
rootNodeName = rootNodeNamespace.Substring("http://foo.com/CSharpNamespace/".Length) + "." +
rootNodeName;
}
}
}
//MessageBox.Show(rootNodeName);
try
{
Type t = DetermineTypeFromName(rootNodeName);
if (t == null)
{
throw new Exception("Could not determine type of serialized string. Type listed as: "+rootNodeName);
}
var s = new XmlSerializer(t);
return s.Deserialize(new StringReader(objectToDeserialize));
// object o = new object();
// MethodInfo castMethod = o.GetType().GetMethod("Cast").MakeGenericMethod(t);
// return castMethod.Invoke(null, new object[] { s.Deserialize(new StringReader(objectToDeserialize)) });
}
catch (InvalidOperationException)
{
return null;
}
}
そして、CommandAndArguments
シリアル化されたときのXMLは次のとおりです。
<?xml version="1.0" encoding="utf-16"?>
<CommandAndArguments xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://foo.com/CSharpNamespace/Foo.Bar">
<Command>I am a command</Command>
<Arguments>
<anyType xsi:type="Foo.Baz.Bat.QueuedFile">
<FileName xmlns="">HelloWorld.txt</FileName>
<DirectoryName xmlns="">C:\foo\bar</DirectoryName>
</anyType>
</Arguments>
</CommandAndArguments>
しかし、逆シリアル化するとCommandAndArguments
、引数がオブジェクトでありXmlNode[]
、最初の項目が属性であり、QueuedFileをタイプとして指定し、他のインデックスがプロパティの要素であるオブジェクトが与えられます。しかし、なぜQueuedFile
オブジェクトが再作成されなかったのですか?
これは、C#名前空間と、逆シリアル化を実行しているエンジンが検索または操作できないことに関係しているのQueuedFile
ではないかと思います...しかし、忘れたときに、予期しXmlInclude()
ていなかったことを確認したので、理由はわかりません。QueuedFile
追加したXmlInclude()
ので、エラーは発生せず、逆シリアル化が不完全です。
ヘルプ?私は私が読むために見つけることができるすべてを読み、私が知っているすべてをグーグルにグーグルで検索し、行き詰まっています。私は確かにXMLシリアル化について学ぶことがたくさんありますが、かなり単純なはずの何かでどのように失敗しているのかわかりません(実際には、以前は問題なくほぼ同じようなことをしましたが、唯一の違いはすべてが同じC#名前空間内)。