C# 如何序列化包含其他类的对象的类(递归序列化?)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2169970/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to serialize a class that contains objects of other classes (recursive serializing?)
提问by Johnny
How can I do this? Or will the serializer automatically go with recursion, and serialize all those child objects into XML?
我怎样才能做到这一点?或者序列化程序会自动进行递归,并将所有这些子对象序列化为 XML?
Give me an example how would you serialize classes that contain other classes' objects in themselves! That was the core of this question!
举个例子,你将如何序列化包含其他类对象的类!这就是这个问题的核心!
I've tried this, and it didn't output anything(except the XML header) to the targeted XML file.
我试过了,它没有向目标 XML 文件输出任何内容(除了 XML 标头)。
My problem is that I need to serialize a simple class, that just holds a List object. But, those Entities also hod List objects. (Another plus would be if I could avoid the serialization of some components, because some are derived and have dictionaries in them).
我的问题是我需要序列化一个简单的类,它只包含一个 List 对象。但是,这些实体也包含 List 对象。(另一个好处是,如果我可以避免某些组件的序列化,因为有些组件是派生的并且其中包含字典)。
public void SaveCurrent(string MapFileName)
{
string MapPath = world_.game_.Content.RootDirectory + "/Maps/" + MapFileName + ".xml";
StreamWriter MapWriter = new StreamWriter(MapPath);
Map SavedMap = new Map();
SavedMap.Entities = world_.Entities;
XmlSerializer xSerializer = new XmlSerializer(SavedMap.GetType());
xSerializer.Serialize(MapWriter, SavedMap);
MapWriter.Close();
}
That's the piece of code that does the serialization.
那是执行序列化的一段代码。
public class Map
{
internal string MapName;
internal string MapDescription;
internal string MapAuthor;
public List<Entity> Entities = new List<Entity>();
}
And this is the class that's serialized. Could internals be counted as publics, if the serialization is called from the same assembly?The code throws exception at the SavedMap.GetType()
function, and I've tried typeof(Map)
too, but without success. I guess it's because I need some other way to handle each new class (deep serialization) how do I do that?
这是序列化的类。如果从同一个程序集中调用序列化,内部是否可以算作公共?代码在SavedMap.GetType()
函数上抛出异常,我也尝试typeof(Map)
过,但没有成功。我想这是因为我需要其他一些方法来处理每个新类(深度序列化)我该怎么做?
Also, I've found on some examples, that there are no interface inheritance or attributes, therefore I didn't add those either, but I'm planning to use IXmlSerializable, though I don't know how to call another serialization inside WriteXML implementation.
此外,我在一些示例中发现,没有接口继承或属性,因此我也没有添加这些,但我计划使用 IXmlSerializable,尽管我不知道如何在 WriteXML 中调用另一个序列化执行。
采纳答案by Sylvestre Equy
About the type problem that Josh Einstein mentionned, you do not have to work with the XmlInclude attribute : you can also pass the list of types to the serializer (signature being XmlSerializer(Type baseType, Type[] extraTypes)
). This should be done especially if there's a chance that the extra types list grow over time.
关于 Josh Einstein 提到的类型问题,您不必使用 XmlInclude 属性:您还可以将类型列表传递给序列化程序(签名为XmlSerializer(Type baseType, Type[] extraTypes)
)。尤其是在额外类型列表可能会随着时间增长的情况下,尤其应该这样做。
Finding the extra-types can be either done through reflection over the object to be serialized or reflection at startup on the loaded assemblies to fetch any needed types.
可以通过对要序列化的对象进行反射或在启动时对加载的程序集进行反射以获取任何需要的类型来查找额外类型。
EDIT : raw example :
编辑:原始示例:
public abstract class Animal
{
}
public class Dog : Animal
{
}
public class Cat : Animal
{
}
public static class AnimalSerializer
{
public static void Serialize(List<Animal> animals, Stream stream)
{
List<Type> animalTypes = new List<Type>();
foreach (Animal animal in animals)
{
Type type = animal.GetType();
if (!animalTypes.Contains(type))
{
animalTypes.Add(type);
}
}
XmlSerializer serializer = new XmlSerializer(typeof(List<Animal>), animalTypes.ToArray());
serializer.Serialize(stream, animals);
}
}
回答by Josh
It will serialize the entire object graph (the object and any objects it exposes through public members, recursively) as long as all objects in the graph are serializable. Different serializers have different rules for what is serializable. For example the XmlSerializer needs a default public constructor.
只要图中的所有对象都是可序列化的,它将序列化整个对象图(对象及其通过公共成员公开的任何对象,递归)。不同的序列化器对于可序列化的内容有不同的规则。例如,XmlSerializer 需要一个默认的公共构造函数。
Also, the XML serializer needs to be able to tell what kind of types it will serialize based only on the type info and attributes on those types. So say for example you have a class that has a property of type Animal, yet at runtime XmlSerializer finds an object of type Dog in there. To support this you will need to use the XmlIncludeattribute to let it know ahead of time that it needs to support Dog.
此外,XML 序列化程序需要能够仅根据这些类型的类型信息和属性来判断它将序列化的类型。例如,假设您有一个具有 Animal 类型属性的类,但在运行时 XmlSerializer 在其中找到了 Dog 类型的对象。为了支持这一点,您需要使用XmlInclude属性提前让它知道它需要支持 Dog。
In order to keep parts of the object graph out of the serialized output, you would use the XmlIgnoreattribute. Different serializers also have different attributes for including/ignoring, etc.
为了将部分对象图保留在序列化输出之外,您将使用XmlIgnore属性。不同的序列化器也有不同的包含/忽略等属性。
Hope this helps clarify a little bit. You may also want to read up on this topic in MSDN.
回答by Kris Krause
How much control do you need? You can always implement IXmlSerializable -
你需要多少控制?你总是可以实现 IXmlSerializable -
http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx
http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable.aspx
回答by pr0gg3r
Add Serializable and XmlInclude your class:
添加 Serializable 和 XmlInclude 你的类:
[System.Serializable]
[System.Xml.Serialization.XmlInclude(typeof(Entity))]
public class Map
{
internal string MapName;
internal string MapDescription;
internal string MapAuthor;
public List<Entity> Entities = new List<Entity>();
}
Usage:
用法:
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Map));
serializer.Serialize(mapWriter, savedMap);