微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在.NET中反序列化为本地集合?

如何解决如何在.NET中反序列化为本地集合?

我正在尝试在.NET中建立数据管道。给我一个xsd,并用XML Schema Definition Tool生成了代表对象模型的C#类。为了将这些数据加载到我的数据存储中,我需要将来自XML的数据转换为与我的应用程序模式和collection / dedupe元素匹配的结构。为此,我有一个解析器类,该类将读取文件并将内容加载到本地集合中,然后将其加载到我的数据库中。我看到两个选项可以做到这一点-

  1. 使用XmlReader手动遍历XML,并提取所需的数据,并将其加载到流中的本地集合中。这是不理想的,因为它没有利用我给定的强类型/严格xsd的优势,并且需要大量的硬编码,例如while (reader.Read()),检查特定的XML节点,然后使用“阅读器” .GetAttribute(“ HardCodedString”)。
  2. 使用XmlSerializer立即对整个文件进行反序列化,然后循环遍历反序列化的集合并插入到我的本地集合中。这是不理想的,因为文件可能很大,并且此方法迫使我循环遍历所有数据两次(一次进行反序列化,一次将数据提取到本地集合中)。

理想情况下,我想以某种方式注册要执行的委托,因为每个对象都被反序列化以插入到我的本地集合中。框架中是否可以执行此操作?要求如下:

  1. Performant-仅循环一次数据。
  2. 功能-反序列化期间将数据插入本地集合中。
  3. Maintainable-使用通过xsd生成的强类型类。

我创建了一个最小的例子来说明我的观点。

示例XML文件

<Hierarchy xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.example.com/example">
    <Children>
        <Child ChildId="1" ChildName="First">
            <Parents>
                <Parent ParentId="1" ParentName="First" RelationshipStart="1900-01-01T00:00:00"/>
                <Parent ParentId="2" ParentName="Second" RelationshipStart="2000-01-01T00:00:00"/>
            </Parents>
        </Child>
        <Child ChildId="2" ChildName="Second">
            <Parents>
                <Parent ParentId="2" ParentName="Second" RelationshipStart="1900-01-01T00:00:00"/>
                <Parent ParentId="3" ParentName="Third" RelationshipStart="2000-01-01T00:00:00"/>
            </Parents>
        </Child>
    </Children>
</Hierarchy>

我要加载的本地收藏集:

public Dictionary<int,string> Parents { get; }
public Dictionary<int,string> Children { get; }
public List<Relationship> Relationships { get; }

手动版本(不可维护,不使用xsd):

public void ParseFileManually(string fileName)
{
    using (var reader = XmlReader.Create(fileName))
    {
        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element && reader.Name == "Hierarchy")
            {
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element && reader.Name == "Child")
                    {
                        int childId = int.Parse(reader.GetAttribute("ChildId"));
                        string childName = reader.GetAttribute("ChildName");
                        Children[childId] = childName;

                        while (reader.Read())
                        {
                            if (reader.NodeType == XmlNodeType.Element && reader.Name == "Parent")
                            {
                                int parentId = int.Parse(reader.GetAttribute("ParentId"));
                                string parentName = reader.GetAttribute("ParentName");
                                DateTime relationshipStart = DateTime.Parse(reader.GetAttribute("RelationshipStart"));
                                
                                Parents[parentId] = parentName;
                                Relationships.Add(
                                    new Relationship{
                                        ParentId = parentId,ChildId = childId,Start = relationshipStart
                                    });
                            }
                            else if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "Child")
                            {
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
}

反序列化版本(两次遍历数据):

public void ParseFileWithDeserialize(string fileName)
{
    var serializer = new XmlSerializer(typeof(Hierarchy));
    using (var fileStream = new FileStream(fileName,FileMode.Open))
    {
        var fileData = (Hierarchy) serializer.Deserialize(fileStream);
        foreach (var child in fileData.Children)
        {
            Children[child.ChildId] = child.ChildName;

            foreach (var parent in child.Parents)
            {
                Parents[parent.ParentId] = parent.ParentName;
                Relationships.Add(
                    new Relationship
                    {
                        ParentId = parent.ParentId,ChildId = child.ChildId,Start = parent.RelationshipStart
                    });
            }
        }
    }
}

解决方法

如果使用这些定义,则应使用一些批注从XML的正确字段中获取数据;

public class Hierarchy
{ 
    public Hierarchy()
    {
        Children = new List<Child>();
    }
    public List<Child> Children { get; set; }
}
public class Child
{
    public Child()
    {
        Parents = new List<Parent>();
    }
    [XmlAttribute("ChildId")]
    public int ChildId { get; set; }
    [XmlAttribute("ChildName")]
    public string ChildName { get; set; }
    public List<Parent> Parents { get; set; }
}
public class Parent
{
    [XmlAttribute("ParentId")]
    public int ParentId { get; set; }
    [XmlAttribute("ParentName")]
    public string ParentName { get; set; }
    [XmlAttribute("RelationshipStart")]
    public DateTime RelationshipStart { get; set; }
}

然后,您应该可以将代码简化为;

    public static Hierarchy Deserialize(string fileName)
    {
        using (var fileStream = new StreamReader(fileName,Encoding.UTF8))
        {
            XmlSerializer ser = new XmlSerializer(typeof(Hierarchy));
            return (Hierarchy)ser.Deserialize(fileStream);
        }
    }

要对其进行测试,您可以创建一个示例数据集并将其序列化为文件,然后使用上面的代码将其读回

    public static void Serialize(Hierarchy h,string fileName)
    {
        System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(Hierarchy));
        StreamWriter sw = new StreamWriter(fileName,false,Encoding.UTF8);
        ser.Serialize(sw,h);
    }

测试代码

    static void Test()
    {
        Hierarchy h = new Hierarchy();
        Parent p1 = new Parent() { ParentId = 1,ParentName = "First",RelationshipStart = DateTime.Now };
        Parent p2 = new Parent() { ParentId = 2,ParentName = "Second",RelationshipStart = DateTime.Now };
        Parent p3 = new Parent() { ParentId = 3,ParentName = "Third",RelationshipStart = DateTime.Now };
        Child c1 = new Child() { ChildId = 1,ChildName = "First" };
        c1.Parents.Add(p1);
        c1.Parents.Add(p2);
        Child c2 = new Child() { ChildId = 2,ChildName = "Second" };
        c2.Parents.Add(p2);
        c2.Parents.Add(p3);
        h.Children.Add(c1);
        h.Children.Add(c2);
        Serialize(h,AppContext.BaseDirectory + "Text.xml");
        Hierarchy hReadBack = Deserialize(AppContext.BaseDirectory + "Text.xml");
    }

编辑:回答您的问题

使用这些类

public class Hierarchy
{ 
    public Hierarchy()
    {
        Children = new List<Child>();
    }
    public List<Child> Children { get; set; }

    private Dictionary<int,string> _parents;
    private Dictionary<int,string> _childrenList;
    private List<Relationship> _relationships;
    private void CalcuateLists()
    {
        _parents = new Dictionary<int,string>();
        _childrenList = new Dictionary<int,string>();
        _relationships = new List<Relationship>();
        foreach (Child c in this.Children)
        {
            if (!_childrenList.ContainsKey(c.ChildId))
            {
                _childrenList.Add(c.ChildId,c.ChildName);
            }
            foreach (Parent p in c.Parents)
            {
                if (!_parents.ContainsKey(p.ParentId))
                {
                    _parents.Add(p.ParentId,p.ParentName);
                }
                if (_relationships.FirstOrDefault(dat => dat.ParentId == p.ParentId && dat.ChildId == c.ChildId) == null)
                {
                    _relationships.Add(new Relationship() { ChildId = c.ChildId,ParentId = p.ParentId,Start = p.RelationshipStart });
                }
            }
        }
    }
    public Dictionary<int,string> Parents { 
        get
        {
            if (_parents == null)
                CalcuateLists();
            return _parents;
        }
    }
    public Dictionary<int,string> ChildrenList {
        get
        {
            if (_childrenList == null)
                CalcuateLists();
            return _childrenList;
        }
    }
    public List<Relationship> Relationships { 
        get
        {
            if (_relationships == null)
                CalcuateLists();
            return _relationships;
        }
    }
}
public class Child
{
    public Child()
    {
        Parents = new List<Parent>();
    }
    [XmlAttribute("ChildId")]
    public int ChildId { get; set; }
    [XmlAttribute("ChildName")]
    public string ChildName { get; set; }
    public List<Parent> Parents { get; set; }
}
public class Parent
{
    [XmlAttribute("ParentId")]
    public int ParentId { get; set; }
    [XmlAttribute("ParentName")]
    public string ParentName { get; set; }
    [XmlAttribute("RelationshipStart")]
    public DateTime RelationshipStart { get; set; }
}

然后您的测试代码变为

public static void Test()
{
    Hierarchy h = new Hierarchy();
    Parent p1 = new Parent() { ParentId = 1,RelationshipStart = DateTime.Now };
    Parent p2 = new Parent() { ParentId = 2,RelationshipStart = DateTime.Now };
    Parent p3 = new Parent() { ParentId = 3,RelationshipStart = DateTime.Now };
    Child c1 = new Child() { ChildId = 1,ChildName = "First" };
    c1.Parents.Add(p1);
    c1.Parents.Add(p2);
    Child c2 = new Child() { ChildId = 2,ChildName = "Second" };
    c2.Parents.Add(p2);
    c2.Parents.Add(p3);
    h.Children.Add(c1);
    h.Children.Add(c2);
    Serialize(h,AppContext.BaseDirectory + "Text.xml");
    Hierarchy hReadBack = Deserialize(AppContext.BaseDirectory + "Text.xml");

    Dictionary<int,string> Parents = hReadBack.Parents;
    Dictionary<int,string> Children = hReadBack.ChildrenList;
    List<Relationship> Relationships = hReadBack.Relationships;
}

编辑

直接获得结果而无需循环

您将需要此类

public class Relationship
{
    public int ParentId { get; set; }
    public int ChildId { get; set; }
    public DateTime Start { get; set; }
}  

这个选择

// Get a list of child ids and names
Dictionary<int,string> Children = (from c in hReadBack.Children select new { ChildId = c.ChildId,Name = c.ChildName}).ToDictionary(dat => dat.ChildId,dat => dat.Name);
// Get a parent ids and names
Dictionary<int,string> Parents = (from p in hReadBack.Children.SelectMany(i => i.Parents) select new { ParentId = p.ParentId,Name = p.ParentName }).Distinct().ToDictionary(dat => dat.ParentId,dat => dat.Name);
// Get the relationships
List<Relationship> Relationship = (from Child c in hReadBack.Children from Parent p in c.Parents select new Relationship() { ChildId = c.ChildId,Start = p.RelationshipStart }).ToList();

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。