比较两个自定义LIST对象

时间:2014-02-04 15:20:23

标签: c# linq lambda

我有检查的方案

1)如果来自empDb的{​​{1}}中的任何道具(EmployeeObject)返回empXml。否则返回true

false

所以让我直截了当,我正在尝试确定列表public class EmployeeObject { public Int32 Id { get; set; } public string Title { get; set; } public string Desc { get; set; } ..... } IList<EmployeeObject> empDb = PopulateFromDb(); //calling ado.net IList<EmployeeObject> empXml = PopulateFromXml(); //deserializing xml 是否是列表empXml的子集?

到目前为止已经尝试过;但即使我已经检查了两个列表中的数据,它也会返回false,除非我在表达式中做错了,否则它应该返回true。

empDb

//at least one MATCH
empDb.Any(a => empXml.Contains(a));

2 个答案:

答案 0 :(得分:3)

如果您没有在Equals课程中实施GetHashCodeEmployeeObject,那么将通过引用对员工进行比较。你肯定会在这里有不同的实例,因为当你从数据库中读取数据时会创建第一个列表,而当你反序列化xml时会创建第二个列表。因此,即使具有相同所有字段值的员工也会被视为不同。

如果您只想按员工ID检查匹配项,那么您可以将序列投影到ID,然后使用Intersect检查是否存在匹配

// at least one employee with equal Id
empDb.Select(e => e.Id).Intersect(empXml.Select(e => e.Id)).Any()

如果您想按字段值而不是引用来比较员工,您有几种选择。如果您不能或不想更改EmployeeObject类的实现并覆盖其Equals和GetHashCode方法,那么您可以为员工创建自定义 comparer

public class EmployeeComparer : IEqualityComparer<EmployeeObject>
{
    public bool Equals(EmployeeObject x, EmployeeObject y)
    {
        return x.Id == y.Id
            && x.Title == y.Title
            && x.Desc == y.Desc;
    }

    public int GetHashCode(EmployeeObject obj)
    {
        int code = 19;
        code = code * 23 + obj.Id.GetHashCode();
        code = code * 23 + obj.Title.GetHashCode();
        code = code * 23 + obj.Desc.GetHashCode();
        return code;
    }
}

然后你可以使用这个比较器:

empDb.Intersect(empXml, new EmployeeComparer()).Any()

或者您可以将员工投射到匿名对象(其默认实现为Equals和GetHashCode):

empDb.Select(e => new { e.Id, e.Title, e.Desc })
     .Intersect(empXml.Select(e => new { e.Id, e.Title, e.Desc })).Any()

覆盖这些方法:

public class EmployeeObject
{
    public Int32 Id { get; set; }
    public string Title { get; set; }
    public string Desc { get; set; }

    public override int GetHashCode()
    {
        int code = 19;
        code = code * 23 + Id.GetHashCode();
        code = code * 23 + Title.GetHashCode();
        code = code * 23 + Desc.GetHashCode();
        return code;
    }

    public override bool Equals(object obj)
    {
        EmployeeObject other = obj as EmployeeObject;
        if (other == null)
            return false;

        if (ReferenceEquals(this, other))
            return true;

        return Id == other.Id && 
               Title == other.Title && Desc == other.Desc;                 
    }
}

您的代码将有效。或者您可以使用Intersect:

empDb.Intersect(empXml).Any()

答案 1 :(得分:2)

如果Id是您可能要写的实体的主键:

var set = new HashSet<int>(empXml.Select(x => x.Id)); //For faster lookup
empDb.Any(a => set.Contains(a.Id));

但是,如果您需要匹配所有属性,则需要覆盖EqualsGetHashCode
(此实现也匹配属性的空值)

public class EmployeeObject : IEquatable<EmployeeObject>
{
        public bool Equals(EmployeeObject other)
        {
            return Id == other.Id && 
                   string.Equals(Title, other.Title) && 
                   string.Equals(Desc, other.Desc);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != this.GetType()) return false;
            return Equals((EmployeeObject) obj);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                var hashCode = Id;
                hashCode = (hashCode*397) ^ (Title != null ? Title.GetHashCode() : 0);
                hashCode = (hashCode*397) ^ (Desc != null ? Desc.GetHashCode() : 0);
                return hashCode;
            }
        }

        public Int32 Id { get; set; }
        public string Title { get; set; }
        public string Desc { get; set; }
    }

写道:

var set = new HashSet<EmployeeObject>(empXml); //For faster lookup
empDb.Any(a => set.Contains(a));