【问题标题】:Compare two objects based on criteria根据标准比较两个对象
【发布时间】:2019-07-20 03:05:01
【问题描述】:

我需要比较两个List<object>,但在比较具有“字符串”值的属性时我不想要区分大小写的比较

我有一堂课:

class User
{
    public int Id { get;set; }
    public string name { get;set; }
}

我有 2 个列表 List<User> olduserList<User> newuser。我需要比较两个列表,但在比较时我应该忽略“名称”字段的区分大小写并获取 olduser 中的值而不是 newuser 中的值的一部分。

List<User> obsoleteUsers = olduser.Except(newuser).ToList();

我需要添加一个条件,在比较两个列表时,请忽略“名称”字段的大小写。

【问题讨论】:

  • Except 是否将比较器作为参数?
  • 在比较 User 对象的相等性时,是否希望使用这种比较始终?或者只是在这个特定场景中(比较这些列表)?
  • 比较应该考虑ID还是只考虑名字?以下答案之一检查两者,而另一个仅比较名称
  • @mjwills 永远是的
  • @pinkfloydx33 只需要名字

标签: c# string linq


【解决方案1】:

您可以使用自定义IEqualityComparer&lt;T&gt;

class UserNameComparer : IEqualityComparer<User>
{
    public UserNameComparer(StringComparer comparer)
    {
        if (comparer == null) throw new ArgumentNullException(nameof(comparer));
        this.Comparer = comparer;
    }

    public StringComparer Comparer { get; }

    public bool Equals(User x, User y)
    {
        if (x == null || y == null) return true;
        return Comparer.Equals(x.name, y.name);
    }

    public int GetHashCode(User obj)
    {
        return Comparer.GetHashCode(obj?.name);
    }
}

你在Except(或其他LINQ方法)中使用它:

List<User> obsoleteUsers = olduser
    .Except(newuser, new UserNameComparer(StringComparer.InvariantCultureIgnoreCase))
    .ToList();

通过这种方式,您可以针对不同的需求实现多个比较器,而无需更改原始类及其识别重复项的方式(例如通过ID-property)。

注意Except(和其他基于集合的方法,如Distinct)使用GetHashCode 快速检查一个对象是否等于另一个。这就是为什么你的类应该覆盖EqualsGetHashCode(总是一起)以支持在基于集合的集合中使用(如HashSet&lt;T&gt;Dictionary&lt;TKey, TValue&gt;)。否则,您将使用来自 System.Object 的版本,它只比较引用而不是属性。

【讨论】:

  • if (Comparer == null) 有错字,应该是if (comparer == null)
【解决方案2】:

如果您想用自己的规则比较相等性,让我们实现EqualsGetHashCode 方法:

  class User : IEquatable<User> {
    // Dangerous practice: Id (and name) usually should be readonly:
    // we can put instance into, say, dictionary and then change Id loosing the instance 
    public int Id { get; set; }
    public string name { get; set; }

    public bool Equals(User other) {
      if (null == other)
        return false;

      return  
        Id == other.Id && 
        string.Equals(name, other.name, StringComparison.OrdinalIgnoreCase);
    }

    public override bool Equals(object obj) => Equals(obj as User);

    public override int GetHashCode() => Id;
  }

那你可以照常输入Except

【讨论】:

  • 注意GetHashCode 正在使用可变属性并且在对象位于集合/字典中时修改Id 可能会导致它“丢失”
猜你喜欢
  • 1970-01-01
  • 2021-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-02
  • 2014-01-26
相关资源
最近更新 更多