【问题标题】:Overriding Equals on IEquatable覆盖 IEquatable 上的等于
【发布时间】:2014-12-31 11:45:36
【问题描述】:

我尝试使用以下方法阻止人们更改 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 的 Vessel 是我尝试匹配的 currentVessel 的不同实例,引用导致不相等,与相等规则有关的事情不是基于 ID。

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

在这种情况下,我想要我自己的基于 id 的自定义规则来实现平等。如何覆盖此方法?

【问题讨论】:

  • 请添加您正在使用的ORM(实体框架、NHibernate等)的标签。

标签: c# .net entity-framework


【解决方案1】:

在这种情况下覆盖 Equals 在这里似乎有点矫枉过正,为什么不这样做

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

【讨论】:

  • 谢谢,但我现在觉得自己像个白痴。当你知道如何嘿时很容易!
【解决方案2】:

改变

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

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

【讨论】:

    【解决方案3】:

    @james 建议的解决方案不是最佳实践。 这就是为什么如果你有一个长长的容器列表应该添加到Hashset<Vessel> contains 方法将只花费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&lt;Vessel&gt; 可以转换为许多泛型集合,例如 List&lt;T&gt;

    来自MSDN

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

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

    【讨论】:

    • 简化类型等于:return Id == other.Id,对象等于返回return vessel != null &amp;&amp; Equals(vessel)。更少的代码,你不会重复逻辑。
    • 在这里声称使用Any 是“不是一个好的解决方案”或“不是最佳实践”是荒谬的。 for 实现 Equals 的参数当然是有效的,但只有 if 性能/列表大小是一个因素 - OP 没有提到。
    猜你喜欢
    • 2016-12-19
    • 1970-01-01
    • 1970-01-01
    • 2014-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多