我正在比较两个复杂对象列表,以找到插入的元素、修改的元素和删除的元素:
小示例
public class pippo
{
public int fluido;
public int abc;
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
List<pippo> lstact= new List<pippo>();
List<pippo> lstprec = new List<pippo>();
lstact.Add(new pippo { abc = 1, fluido = 1 });
lstact.Add(new pippo { abc = 2, fluido = 1 });
lstact.Add(new pippo { abc = 3, fluido = 1 });
lstprec.Add(new pippo { abc = 1, fluido = 1 });
lstprec.Add(new pippo { abc = 2, fluido = 1 });
// compare two list for find item insert, deleted, modified
}
}
要正确解决此问题,应首先使对象具有可比性,然后使用内置列表函数和/或LINQ解决问题。
第一件事:对象比较的基础
在C#中,每个类都派生自类"object"。"object"为每个类提供了一种基本的比较方式,它说:当im是同一个实例(内存中的同一位置(时,那么im等于。
因此:通常,当比较两个对象时,没有定义其他对象,C#不会比较对象的内容(深度比较(,但它确实会检查它是否是同一个对象实例(引用比较(。
所以当我这样做的时候:
var x = new pippo { abc = 1, fluido = 1};
var y = new pippo { abc = 1, fluido = 1};
我比较了这两个对象,它们将不相同,因为它们是两个不同的实例(new关键字使一个新实例完全正确(。
深度比较
但是,当您对String类执行相同操作时:
var x = new String("hello world");
var y = new String("hello world");
如果你把这两个(x==y(进行比较,结果会是一样的。他们是怎么做到的?
他们通过重写"对象"的默认行为,并提供一种将这些对象与其他对象进行比较的新方法,重新定义了字符串比较自身的方式。
看看这里的一个好例子。。
在您的情况下实现深度比较的正确方法是重写"Equals"方法。当您这样做时,覆盖"GetHashcode"方法也是一种很好的做法。他们实际上是成双成对的。事实上,如果您只是重写其中一个方法而不是同时重写这两个方法,编译器甚至会警告您。为pippo这样做看起来是这样的:
public class pippo
{
public int fluido;
public int abc;
public override bool Equals(object obj)
{
// If this and obj do not refer to the same type, then they are not equal.
if (obj.GetType() != this.GetType()) return false;
// Return true if abc and fluido fields match.
var other = (pippo) obj;
return (this.abc == other.abc) && (this.fluido == other.fluido);
}
public override int GetHashCode()
{
//something like this.
return ($"{this.abc}/{this.fluido}").GetHashCode();
}
}
好的,现在C#知道如何检查pippos是否"相等"。现在,我们可以开始使用C#或LINQ的内置列表操作来满足您的需求
例如,要比较列表并获得插入和删除的元素,您可以执行
(这里可能有语法错误,但它应该显示出诀窍:
var newElements = lstact.Where(p=>!lstprec.Contains(p)).ToList();
var deletedElements = lstprec.Where(p=>!lstact.Contains(p)).ToList();
或者通过做这样的事情:
foreach(var p in lstprec)
if(!lstact.Contains(p))
....
正如你所看到的,如果你在pippo类中投资一点,你可以做很多很酷的事情,而且你可以做得很好。。。
这里是linq解决方案:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
List<pippo> lstact = new List<pippo>();
List<pippo> lstprec = new List<pippo>();
lstact.Add(new pippo { abc = 1, fluido = 1 });
lstact.Add(new pippo { abc = 2, fluido = 1 });
lstact.Add(new pippo { abc = 3, fluido = 1 });
lstprec.Add(new pippo { abc = 1, fluido = 1 });
lstprec.Add(new pippo { abc = 2, fluido = 1 });
var matches = (from act in lstact
join prec in lstprec on act equals prec into pr
from prec in pr.DefaultIfEmpty()
select new { act = act, prec = prec }
).ToList();
foreach (var match in matches)
{
if(match.act == null)
{
Console.WriteLine("B does not match A, abc = '{0}', prec = '{1}'", match.prec.abc, match.prec.fluido);
}
else
{
if(match.prec == null)
{
Console.WriteLine("A does not match B, abc = '{0}', prec = '{1}'", match.act.abc, match.act.fluido);
}
else
{
Console.WriteLine("A matches B, abc = '{0}', prec = '{1}'", match.act.abc, match.act.fluido);
}
}
}
Console.ReadLine();
}
}
public class pippo : IEquatable<pippo>
{
public int abc { get;set;}
public int fluido { get;set;}
public Boolean Equals(pippo other)
{
return (this.abc == other.abc) && (this.fluido == other.fluido);
}
public override int GetHashCode()
{
return (this.abc.ToString() + "^" + this.fluido.ToString()).GetHashCode();
}
}
}