以下代码比较两个 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/