Xml 序列化 ICollection [英] Xml Serializing ICollection

查看:24
本文介绍了Xml 序列化 ICollection的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在开发一个具有适度复杂模型的项目,其核心类具有许多属性,这些属性是其他相关类的列表.我们在后端使用 EF 6(代码优先),并且按照有关如何为该环境构建类的指导,我们大量利用了 ICollection:

We're working on a project with a modestly-complex model, the core class of which has a number of properties that are lists of other associated classes. We're using EF 6 (code first) on the back end, and, following guidance on how to construct classes for that environment, we heavily leveraged ICollection<T>:

public class Product
{
    // a few normal properties
    public string Name { get; set; }
    public string Description { get; set; }
    public string Code { get; set; }
    // a large list of ICollection<T> properties
    public virtual ICollection<Rule> Rules { get; set; }
    public virtual ICollection<Update> Updates { get; set; }
    public virtual ICollection<Reference> References { get; set; }
    // more ICollections from here...
}

ICollection 引用的几个类在它们自己内部有集合(例如 RuleICollectionCondition),创建一棵相当深且复杂的树.

Several of the classes referenced by ICollection<T> have collections within themselves (e.g. Rule has ICollection<Condition> Conditions), creating a fairly deep and complex tree.

现在我们的模型几乎完成了,我们已经开始开发业务逻辑和 UI (ASP.NET MVC).系统所需的功能之一是序列化/反序列化 XML 以与另一个系统交互.但是我们发现 XmlSerialization.Serialize() 不起作用,抱怨它不能序列化使用接口的东西.

Now that we have our model nearly finalized, we've moved on to developing business logic and a UI (ASP.NET MVC). One of the required capabilities of the system is to serialize/deserialize XML to interface with another system. But we've discovered that XmlSerialization.Serialize() doesn't work, complaining that it can't serialize something that uses an interface.

当我们开始整个项目时,知道序列化将是一个因素,我们构建了一组 XSD 并使用 xsd.exe 为我们生成类,我们已经修改了沉重.但是,该实用程序放入了一堆应该有助于序列化的标记,我们保留了所有标记:

When we started this whole project, knowing that serialization was going to be a factor, we constructed a set of XSDs and used xsd.exe to generate classes for us, which we've since modified heavily. However, the utility put in a bunch of tagging that was supposed to aid in serialization, and we kept it all:

[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlRootAttribute("product", Namespace = "", IsNullable = false)]
public class Product
{
    ....
}

不幸的是,我们遇到了无法序列化的问题,即使我们(理论上)告诉编译器,确实,这个类是可序列化的.并且每个子类都有一组相似的标签.因此,进行了更多的研究......

Unfortunately, we're encountering the problem of not being able to serialize, even though we're (theoretically) telling the compiler that, yes indeed, this class is serializable. And each of the sub-classes has a similar set of tags. So, more research was undertaken...

此处提供的解决方案似乎有很多包袱.关于该主题的其他 SO 答案似乎只是描述了 ICollectionCollection 之间的区别,而没有提供关于 为什么 的太多指导你想避免具体的类.我正在考虑将所有内容迁移到使用 Collection 而不是 ICollection.如果我这样做,我会不会给自己将来带来麻烦?

The solutions offered here seem like they come with a lot of baggage. Other SO answers on the subject just seem to describe the difference between ICollection<T> and Collection<T>, without providing much guidance on why you'd want to avoid the concrete class. I'm considering just migrating everything to using Collection<T> instead of ICollection<T>. Am I going to cause myself problems for the future if I do this?

推荐答案

您是否尝试过 IXmlSerializable?从这个界面你可以控制你写和读的内容.我不确定这是否可以帮助您解决问题.

Have you tried IXmlSerializable? From this interface you can control what you write and read. I am not sure if this can help your problem.

    public CSortedList<string, CBasicStockData> Stocks { get; set; }
    public CSortedList<string, CIndustrySectorExchangeInfo> Exchanges { get; set; }
    public CSortedList<string, CIndustrySectorExchangeInfo> Industries { get; set; }
    public CSortedList<string, CIndustrySectorExchangeInfo> Sectors { get; set; }

    public void WriteXml(XmlWriter writer)
    {
        try
        {
            ///////////////////////////////////////////////////////////
            writer.WriteStartElement("Stocks");
            writer.WriteAttributeString("num", Stocks.Count.ToString());
            foreach (var kv in Stocks)
            {
                writer.WriteStartElement("item");
                foreach (var p in kv.Value.WritableProperties)
                {
                    var value = p.GetValue(kv.Value);
                    var str = (value == null ? string.Empty : value.ToString());
                    writer.WriteAttributeString(p.Name, str);
                }
                writer.WriteEndElement();
            }
            writer.WriteEndElement();

            ///////////////////////////////////////////////////////////
            foreach (var propInfo in this.WritableProperties)
            {
                if (propInfo.Name == "Stocks") continue;
                dynamic prop = propInfo.GetValue(this);

                writer.WriteStartElement(propInfo.Name);
                writer.WriteAttributeString("num", prop.Count.ToString());
                foreach (var kv in prop)
                {
                    writer.WriteStartElement("item");
                    foreach (var p in kv.Value.WritableProperties)
                    {
                        var value = p.GetValue(kv.Value);
                        var str = (value == null ? string.Empty : value.ToString());
                        writer.WriteAttributeString(p.Name, str);
                    }
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
            throw ex;
        }
    }

    public void ReadXml(XmlReader reader)
    {
        var propName = string.Empty;
        while (reader.Read() &&
            !(reader.NodeType == XmlNodeType.EndElement && reader.LocalName == this.GetType().Name))
        {
            if (reader.Name != "item")
            {
                propName = reader.Name;
                continue;
            }

            switch (propName)
            {
                case "Stocks":
                    {
                        var obj = new CBasicStockData();
                        foreach (var propInfo in obj.WritableProperties)
                        {
                            var value = reader.GetAttribute(propInfo.Name);
                            if (value == null)  //we may add new property to class after the file is created
                                continue;
                            propInfo.SetValue(obj, Convert.ChangeType(value, propInfo.PropertyType));
                        }
                        this.Stocks.Add(obj.Symbol, obj);
                        break;
                    }
                case "Exchanges":
                case "Industries":
                case "Sectors":
                    {
                        var obj = new CIndustrySectorExchangeInfo();
                        foreach (var p in obj.WritableProperties)
                        {
                            var value = reader.GetAttribute(p.Name);
                            if (value == null)
                                continue;
                            p.SetValue(obj, Convert.ChangeType(value, p.PropertyType));
                        }
                        var propInfo = this.WritableProperties.Find(x => x.Name == propName);
                        dynamic prop = propInfo.GetValue(this);
                        prop.Add(obj.Name, obj);
                        break;
                    }
                default:
                    break;
            }
        }
    }

    public static string XML_Serialize<T>(string filename, T myObject) where T : IXmlSerializable
    {
        XmlSerializer xmlSerializer = new XmlSerializer(myObject.GetType());
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;

        using (StringWriter stringWriter = new StringWriter())
        using (XmlWriter writer = XmlWriter.Create(stringWriter, settings)) {
            xmlSerializer.Serialize(writer, myObject);
            var xml = stringWriter.ToString(); // Your xml
            File.WriteAllText(filename, xml);
            return xml;
        }
    }
    public static void XML_DeSerialize<T>(string filename, out T myObject) where T : IXmlSerializable
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
        using (StreamReader reader = new StreamReader(filename)) {
            myObject = (T)xmlSerializer.Deserialize(reader);
        }
    }

这篇关于Xml 序列化 ICollection的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆