简体   繁体   English

如何序列化包含其他类对象的类(递归序列化?)

[英]How to serialize a class that contains objects of other classes (recursive serializing?)

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. 我的问题是我需要序列化一个简单的类,它只包含一个List对象。 But, those Entities also hod List objects. 但是,这些实体也是Lod List对象。 (Another plus would be if I could avoid the serialization of some components, because some are derived and have dictionaries in them). (另一个好处是,如果我可以避免某些组件的序列化,因为一些组件是派生的并且在其中有字典)。

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. 代码在SavedMap.GetType()函数抛出异常,我也尝试了typeof(Map) ,但没有成功。 I guess it's because I need some other way to handle each new class (deep serialization) how do I do that? 我想这是因为我需要一些其他方法来处理每个新类(深度序列化)我该怎么做?

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中调用另一个序列化实现。

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);

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. 此外,XML序列化程序需要能够根据这些类型的类型信息和属性来确定它将序列化的类型。 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. 例如,假设您有一个具有Animal类型属性的类,但在运行时XmlSerializer在那里找到一个类型为Dog的对象。 To support this you will need to use the XmlInclude attribute to let it know ahead of time that it needs to support Dog. 为了支持这一点,您需要使用XmlInclude属性让它提前知道它需要支持Dog。

In order to keep parts of the object graph out of the serialized output, you would use the XmlIgnore attribute. 为了将对象图的一部分保留在序列化输出之外,您将使用XmlIgnore属性。 Different serializers also have different attributes for including/ignoring, etc. 不同的序列化程序也有不同的属性包括/忽略等。

Hope this helps clarify a little bit. 希望这有助于澄清一点。 You may also want to read up on this topic in MSDN . 您可能还想在MSDN中阅读此主题

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

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) ). 关于Josh Einstein提到的类型问题,您不必使用XmlInclude属性:您还可以将类型列表传递给序列化程序(签名为XmlSerializer(Type baseType, Type[] extraTypes) )。 This should be done especially if there's a chance that the extra types list grow over time. 如果额外类型列表有可能随着时间的推移而增长,则应该特别做到这一点。

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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM