简体   繁体   中英

Overriding Equals on IEquatable

I have the following method which I am trying to use to stop people altering the querystring in order to view other peoples details:

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;
}

In the example I am currently debugging currentPerson.Vessels yields 3 vessels in an Icollection<Vessel> one of which has a VesselId of 6 which also happens to be the VesselId of currentVessel however the match is failing and the method is returning false .

I have done some reading on similar SO questions and MSDN documentation and my understanding of what is happening here is because the Vessel which has an ID of 6 within the ICollection is a different instance of the currentVessel I am attempting to match, the reference is resulting in not equal and something to do with the equality rules are not based on ID.

My Person model contains public virtual ICollection<Vessel> Vessels { get; set; } public virtual ICollection<Vessel> Vessels { get; set; } public virtual ICollection<Vessel> Vessels { get; set; } does this mean that I must implement the IEquatable interface on my Vessel model and then override the Equals method.

I want my own custom rules based on id for equality in this instance. How do I override this method?

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

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

The solution suggested by @james is not the best practice. here why if you have a long list of Vessels that should be added to a Hashset<Vessel> contains method will cost only O(1) since it will be indexed on GetHashCode while .Any is an extension method that should iterate through all elements to find the right one and the cost will be O(n)

you could do something like this

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;
        }
    }

Update

the reasons why I have stated it's not a best practice it's that OP stated that he has an ICollection<Vessel> which can be converted to many Generics collections like List<T> for example.

from MSDN

When the search methods of a number of generic collection objects are called. Some of these types and their methods include the following:

  • Some of the generic overloads of the BinarySearch method.
  • The search methods of the List class, including List.Contains(T), List.IndexOf, List.LastIndexOf, and List.Remove.
  • The search methods of the Dictionary class, including ContainsKey and Remove. The search methods of the generic LinkedList class, including LinkedList.Contains and Remove.

change

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

to

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM