在 C# 中反序列化 XML 具有多个专业化/继承的文档
Deserialize XML documents with multiple specialization / inheritance in C#
我有一份 XML 文档,其中包含条目专门化的几种情况,我设法从 here 获得了反序列化它的解决方案。我已经完成了与示例完全相同的操作,并且很有魅力,但是它仅在出现单个专门的 class 时才有效。在链接示例(如上所示)中,假设有另一个 class 专用于 Instrument(例如,Drums)。我如何使用此方法告诉反序列化器何时转换为每个专门的 classes?
序列化对象:
public class Orchestra
{
public Instrument[] Instruments;
}
public class Instrument
{
public string Name;
}
public class Brass:Instrument
{
public bool IsValved;
}
反序列化示例:
public void DeserializeObject(string filename)
{
XmlAttributeOverrides attrOverrides =
new XmlAttributeOverrides();
XmlAttributes attrs = new XmlAttributes();
// Create an XmlElementAttribute to override the Instrument.
XmlElementAttribute attr = new XmlElementAttribute();
attr.ElementName = "Brass";
attr.Type = typeof(Brass);
// Add the XmlElementAttribute to the collection of objects.
attrs.XmlElements.Add(attr);
attrOverrides.Add(typeof(Orchestra), "Instruments", attrs);
// Create the XmlSerializer using the XmlAttributeOverrides.
XmlSerializer s =
new XmlSerializer(typeof(Orchestra), attrOverrides);
FileStream fs = new FileStream(filename, FileMode.Open);
Orchestra band = (Orchestra) s.Deserialize(fs);
Console.WriteLine("Brass:");
/* The difference between deserializing the overridden
XML document and serializing it is this: To read the derived
object values, you must declare an object of the derived type
(Brass), and cast the Instrument instance to it. */
Brass b;
foreach(Instrument i in band.Instruments)
{
b = (Brass)i;
Console.WriteLine(
b.Name + "\n" +
b.IsValved);
}
}
我试过添加另一个属性覆盖但它不起作用,我也尝试制作两个单独的反序列化器(每个都有一个属性覆盖 属性 我想投射到一个对象)它既不工作,因为它无法转换其他类型的对象,导致类型异常。
有什么想法吗?
如果您可以控制 .cs 文件,您可以像这样将属性直接添加到主 class,序列化可以使用属性完全控制,在极端情况下,您可以实现 IXmlSerializable 接口.
我在这里写了一个简单的例子,但是你应该提供一个例子说明它对你不起作用的地方以及你得到的异常,以便看到你的具体问题。序列化和反序列化时有很多事情可能会失败,异常会告诉您原因。例如,如果 class 不是 public 它将抛出异常。
public class Program
{
public class Orchestra
{
public Instrument[] Instruments {get; set;}
}
[XmlInclude(typeof(Brass))]
[XmlInclude(typeof(Guitar))]
public class Instrument
{
public string Name { get; set; }
[XmlIgnore]
public string DoNotSerialize { get; set; }
}
public class Brass : Instrument
{
public bool IsValved { get; set; }
public override string ToString()
{
return string.Format("This is a{0} Brass.",IsValved?" valved":"n unvalved");
}
}
public class Guitar: Instrument
{
public int Strings { get; set; }
public override string ToString()
{
return String.Format("This is a {0} string Guitar.", Strings);
}
}
static XmlSerializer s;
static void Main(string[] args)
{
s = new XmlSerializer(typeof(Orchestra));
serialize("%temp%test.xml");
deserialize("%temp%test.xml");
Console.ReadLine();
}
static void serialize(string filename)
{
Orchestra o = new Orchestra();
o.Instruments = new Instrument[]
{
new Brass
{
IsValved=true
},
new Brass {IsValved=false },
new Guitar {Strings=12 }
};
using (FileStream fs = new FileStream(filename, FileMode.Create))
{
s.Serialize(fs, o);
}
}
static void deserialize(string filename)
{
Orchestra band;
using (FileStream fs = new FileStream(filename, FileMode.Open))
{
band = (Orchestra)s.Deserialize(fs);
}
foreach (Instrument i in band.Instruments)
{
Console.WriteLine("{0}: {1}", i.GetType(), i.ToString());
}
}
}
我有一份 XML 文档,其中包含条目专门化的几种情况,我设法从 here 获得了反序列化它的解决方案。我已经完成了与示例完全相同的操作,并且很有魅力,但是它仅在出现单个专门的 class 时才有效。在链接示例(如上所示)中,假设有另一个 class 专用于 Instrument(例如,Drums)。我如何使用此方法告诉反序列化器何时转换为每个专门的 classes?
序列化对象:
public class Orchestra
{
public Instrument[] Instruments;
}
public class Instrument
{
public string Name;
}
public class Brass:Instrument
{
public bool IsValved;
}
反序列化示例:
public void DeserializeObject(string filename)
{
XmlAttributeOverrides attrOverrides =
new XmlAttributeOverrides();
XmlAttributes attrs = new XmlAttributes();
// Create an XmlElementAttribute to override the Instrument.
XmlElementAttribute attr = new XmlElementAttribute();
attr.ElementName = "Brass";
attr.Type = typeof(Brass);
// Add the XmlElementAttribute to the collection of objects.
attrs.XmlElements.Add(attr);
attrOverrides.Add(typeof(Orchestra), "Instruments", attrs);
// Create the XmlSerializer using the XmlAttributeOverrides.
XmlSerializer s =
new XmlSerializer(typeof(Orchestra), attrOverrides);
FileStream fs = new FileStream(filename, FileMode.Open);
Orchestra band = (Orchestra) s.Deserialize(fs);
Console.WriteLine("Brass:");
/* The difference between deserializing the overridden
XML document and serializing it is this: To read the derived
object values, you must declare an object of the derived type
(Brass), and cast the Instrument instance to it. */
Brass b;
foreach(Instrument i in band.Instruments)
{
b = (Brass)i;
Console.WriteLine(
b.Name + "\n" +
b.IsValved);
}
}
我试过添加另一个属性覆盖但它不起作用,我也尝试制作两个单独的反序列化器(每个都有一个属性覆盖 属性 我想投射到一个对象)它既不工作,因为它无法转换其他类型的对象,导致类型异常。
有什么想法吗?
如果您可以控制 .cs 文件,您可以像这样将属性直接添加到主 class,序列化可以使用属性完全控制,在极端情况下,您可以实现 IXmlSerializable 接口.
我在这里写了一个简单的例子,但是你应该提供一个例子说明它对你不起作用的地方以及你得到的异常,以便看到你的具体问题。序列化和反序列化时有很多事情可能会失败,异常会告诉您原因。例如,如果 class 不是 public 它将抛出异常。
public class Program
{
public class Orchestra
{
public Instrument[] Instruments {get; set;}
}
[XmlInclude(typeof(Brass))]
[XmlInclude(typeof(Guitar))]
public class Instrument
{
public string Name { get; set; }
[XmlIgnore]
public string DoNotSerialize { get; set; }
}
public class Brass : Instrument
{
public bool IsValved { get; set; }
public override string ToString()
{
return string.Format("This is a{0} Brass.",IsValved?" valved":"n unvalved");
}
}
public class Guitar: Instrument
{
public int Strings { get; set; }
public override string ToString()
{
return String.Format("This is a {0} string Guitar.", Strings);
}
}
static XmlSerializer s;
static void Main(string[] args)
{
s = new XmlSerializer(typeof(Orchestra));
serialize("%temp%test.xml");
deserialize("%temp%test.xml");
Console.ReadLine();
}
static void serialize(string filename)
{
Orchestra o = new Orchestra();
o.Instruments = new Instrument[]
{
new Brass
{
IsValved=true
},
new Brass {IsValved=false },
new Guitar {Strings=12 }
};
using (FileStream fs = new FileStream(filename, FileMode.Create))
{
s.Serialize(fs, o);
}
}
static void deserialize(string filename)
{
Orchestra band;
using (FileStream fs = new FileStream(filename, FileMode.Open))
{
band = (Orchestra)s.Deserialize(fs);
}
foreach (Instrument i in band.Instruments)
{
Console.WriteLine("{0}: {1}", i.GetType(), i.ToString());
}
}
}