重写IEquatable上的Equals

本文关键字:Equals 上的 IEquatable 重写 | 更新日期: 2023-09-27 18:28:58

我尝试使用以下方法来阻止人们更改querystring以查看其他人的详细信息:

public static bool IsCurrentUserAuthorisedVessel(HttpRequest request)
{
    Guid currentUser = GetCurrentUserId();
    PersonRepository repo = new PersonRepository();
    VesselRepository vesselRepo = new VesselRepository();
    Person currentPerson = repo.GetPersonByUser(currentUser);
    int qs = int.Parse(request.QueryString["VesselId"]);
    Vessel currentVessel = vesselRepo.GetVessel(qs);
    if (!String.IsNullOrEmpty(request.QueryString["VesselId"]))
    {       
        if (IsCurrentUserAdmin())
        {
            return true;  //Always return true for admin                  
        }
        else
        {
            if (currentPerson.Vessels.Contains(currentVessel))
            {
                return true;
            }
            else
                return false;
        }                
    }
    return true;
}

在我当前调试的示例中,currentPerson.VesselsIcollection<Vessel>中产生3个容器,其中一个容器的VesselId为6,恰好也是currentVessel的VesselId,但是匹配失败,该方法返回false

我已经阅读了一些类似的SO问题和MSDN文档,我对这里发生的事情的理解是,因为ICollection中ID为6的船只是我试图匹配的当前船只的不同实例,引用导致不相等,并且与相等规则有关的事情不是基于ID的。

我的Person模型包含public virtual ICollection<Vessel> Vessels { get; set; },这是否意味着我必须在Vessel模型上实现IEquatable接口,然后重写Equals方法。

在这个例子中,我想要我自己的基于id的自定义规则。如何覆盖此方法?

重写IEquatable上的Equals

在这种情况下重写Equals似乎有点过头了,为什么不直接执行呢

currentPerson.Vessels.Any(x => x.ID == currentVessel.ID)

@james提出的解决方案不是最佳实践。为什么如果你有一长串应该添加到Hashset<Vessel>包含的容器的列表,方法将只花费O(1),因为它将在GetHashCode上索引,而.Any是一个扩展方法,应该迭代所有元素以找到正确的元素,并且成本将是O(n)

你可以做一些类似的事情

public class Vessel : IEquatable<Vessel>
    {
        public int Id { get; set; }
        public bool Equals(Vessel other)
        {
            return Id == other.Id ; 
        }
        public override int GetHashCode()
        {
            return Id;
        }
        public override bool Equals(object obj)
        {
            var vessel = obj as Vessel;
            return vessel != null && vessel.Id == this.Id;
        }
    }

更新

我之所以说这不是最佳实践,是因为OP说他有一个ICollection<Vessel>,可以转换成许多泛型集合,例如List<T>

来自MSDN

当调用多个通用集合对象的搜索方法时。其中一些类型及其方法包括:

  • BinarySearch方法的一些通用重载
  • List类的搜索方法,包括List.Contains(T)、List.IndexOf、List.LastIndexOf和List.Remove
  • Dictionary类的搜索方法,包括ContainsKey和Remove。通用LinkedList类的搜索方法,包括LinkedList.Contains和Remove

更改

if (currentPerson.Vessels.Contains(currentVessel))
{
    return true;
}
else
    return false;

return currentPerson.Vessels.Any(x => x.ID == currentVessel.ID)