c# - 有没有办法加快这段在两个 XML 文件中查找数据更改的代码?

标签 c# xml linq performance

以下代码比较两个 XML 文本并返回它们之间的数据更改的集合。

此代码很好但需要尽可能资源友好

在 LINQ 中是否有更快的方法来执行此操作,例如没有创建 XElements 的两个集合并比较它们的每个字段的差异?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace TestXmlDiff8822
{
    class Program
    {
        static void Main(string[] args)
        {
            XDocument xdoc1 = XDocument.Parse(GetXml1());
            XDocument xdoc2 = XDocument.Parse(GetXml2());

            List<HistoryFieldChange> hfcList = GetHistoryFieldChanges(xdoc1, xdoc2);

            foreach (var hfc in hfcList)
            {
                Console.WriteLine("{0}: from {1} to {2}", hfc.FieldName, hfc.ValueBefore, hfc.ValueAfter);  
            }

            Console.ReadLine();
        }

        static public List<HistoryFieldChange> GetHistoryFieldChanges(XDocument xdoc1, XDocument xdoc2)
        {
            List<HistoryFieldChange> hfcList = new List<HistoryFieldChange>();

            var elements1 = from e in xdoc1.Root.Elements()
                           select e;

            var elements2 = from e in xdoc2.Root.Elements()
                           select e;

            for (int i = 0; i < elements1.Count(); i++)
            {
                XElement element1 = elements1.ElementAt(i);
                XElement element2 = elements2.ElementAt(i);

                if (element1.Value != element2.Value)
                {
                    HistoryFieldChange hfc = new HistoryFieldChange();
                    hfc.EntityName = xdoc1.Root.Name.ToString();
                    hfc.FieldName = element1.Name.ToString();
                    hfc.KindOfChange = "fieldDataChange";
                    hfc.ObjectReference = (xdoc1.Descendants("Id").FirstOrDefault()).Value;
                    hfc.ValueBefore = element1.Value;
                    hfc.ValueAfter = element2.Value;
                    hfcList.Add(hfc);
                }
            }

            return hfcList;
        }

        public static string GetXml1()
        {
            return @"
<Customer>
    <Id>111</Id>
    <FirstName>Sue</FirstName>
    <LastName>Smith</LastName>
</Customer>
";
        }



        public static string GetXml2()
        {
            return @"
<Customer>
    <Id>111</Id>
    <FirstName>Sue2</FirstName>
    <LastName>Smith-Thompson</LastName>
</Customer>
";
        }
    }

    public class HistoryFieldChange
    {
        public string EntityName { get; set; }
        public string FieldName { get; set; }
        public string ObjectReference { get; set; }
        public string KindOfChange { get; set; }
        public string ValueBefore { get; set; }
        public string ValueAfter { get; set; }
    }
}

最佳答案

您应该能够使用元素名称上的 linq 连接获取所有具有不同值的元素。

var name = xdoc1.Root.Name.ToString();
var id = (xdoc1.Descendants("Id").FirstOrDefault()).Value;

var diff =  from o in xdoc1.Root.Elements()
        join n in xdoc2.Root.Elements() on o.Name equals n.Name
        where o.Value != n.Value
        select new HistoryFieldChange() {
                EntityName = name,
                FieldName = o.Name.ToString(),
                KindOfChange = "fieldDataChange",
                ObjectReference = id,
                ValueBefore = o.Value,
                ValueAfter = n.Value,
        };

这种方法的优点之一是很容易为多核机器并行化,只需使用 PLinq 和 AsParallel 扩展方法即可。

var diff =  from o in xdoc1.Root.Elements()
        join n in xdoc2.Root.Elements().AsParallel() on o.Name equals n.Name
        where o.Value != n.Value
        ...

瞧,如果查询可以在您的计算机上并行化,那么 PLinq 将自动处理它。这会加快大型文档的速度,但如果您的文档很小,您可以通过使用类似 Parallel.For 的方法并行化调用 GetHistoryFieldChanges 的外部循环来获得更好的速度。

另一个优点是您可以简单地从 GetHistoryFieldChanges 返回 IEnumerable,而不需要浪费时间分配一个 List,项目将在枚举时返回,并且不会执行 Linq 查询直到那时。

IEnumerable<HistoryFieldChange> GetHistoryFieldChanges(...)

这是原始的 1M 次迭代、Yannick 的按顺序和我的非并行 Linq-only 实现的时间。使用 this code 在我的 2.8ghz 笔记本电脑上运行.

Elapsed Orig    3262ms
All Linq        1761ms
In Order Only   2383ms

我注意到一件有趣的事情......在 Debug模式下运行代码,然后在 Release模式下运行代码,编译器可以优化纯 Linq 版本的程度令人惊讶。我认为返回 IEnumerable 在这里对编译器有很大帮助。

关于c# - 有没有办法加快这段在两个 XML 文件中查找数据更改的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2027835/

相关文章:

xml - 为 xsd 属性分配默认值

linq - 如何使用 LINQ-to-SQL 回滚对 WPF DataGrid 控件的更改?

C# 等效于(将变量读取为不同类型)

c# - 如何在当前版本的 Roslyn 中获取 SyntaxToken.Kind?

xml - XSL 使用计数器反转顺序

c# - 如何将 `linq` 的结果返回到 DataTable?

c# - DistinctBy,但忽略null/empty

C# 反序列化根 JSON 未知键

c# - 如何拆分非数字作为分隔符的字符串?

java - XML、XPATH 添加值