简体   繁体   中英

Setting up a simple iequatable class c#

Cant find a simple answer. My problem is I am trying to compare the VALUE of an object in a list to the VALUE of an object...

my class:

public class MatchList 
    {
        public int SomeInt { get; set; }
        public decimal SomeDecimal { get; set; }
    }

I create theMatchList. It seems that I can only compare the object and not the values for object with 'theMatchList.Contains...'

                            MatchList ML = new MatchList();

                            ML.SomeInt = 12;
                            ML.SomeDecimal = 2.3;
                            if (theMatchlist.Contains(ML))
                            {
                                DoSomething;
                            }

How do get to fire 'DoSomething'? Assuming that there is an entry in 'theMatchList' where the values equal 12 and 2.3 respectively. I know it has something to do with iequatable, but I dont quite understand how that works. Thanks in advance!

Your naming is a bit unclear, I assume that you actually have a List<MatchList> that you want to find a particular MatchList in (I suggest renaming MatchList to at least MatchItem in that case and preferable something more descriptive).

Then from the documentation of List<T>.Contains :

This method determines equality by using the default equality comparer, as defined by the object's implementation of the IEquatable<T>.Equals method for T (the type of values in the list).

So you will have to implement IEquatable<T> for your class. In addition, the advice is that

[i]f you implement Equals, you should also override the base class implementations of Object.Equals(Object) and GetHashCode so that their behavior is consistent with that of the IEquatable.Equals method.

If you implement GetHashCode , its result should not change over the lifetime of your object. In most cases, making the class immutable is sufficient. If you need to be able to update the fields, you need to implement GetHashCode differently.

So all in all, if you want to use Contains your class will end up looking something like below:

public class MatchList : IEquatable<MatchList>
{
    // Note: Fields are readonly to satisfy GetHashCode contract
    private readonly int someInt;
    private readonly decimal someDecimal;

    // Public constructor creates immutable object
    public MatchList(int myInt, decimal myDecimal)
    {
         this.someInt = myInt;
         this.myDecimal = myDecimal;
    }

    // Properties are now read-only too.
    public int SomeInt { get { return this.someInt; } }
    public decimal SomeDecimal { get { return this.someDecimal; } }

    // Implementation of IEquatable<MatchList>
    public bool Equals( MatchList other )
    {
      return (other != null) 
          && (this.SomeInt == other.SomeInt)
          && (this.SomeDecimal == other.SomeDecimal);
    }

    // Override of Object.Equals
    // Calls the IEquatable.Equals version if possible.
    public override bool Equals( object obj )
    {
        return (obj is MatchList) && this.Equals(obj as MatchList);
    }

    public override int GetHashCode()
    { 
        return (this.someInt * 17) ^ this.someDecimal.GetHashCode();
    }
}

As I commented, your question is pretty unclear so I'll do my best to explain the concept.

It's pretty likely what you were trying to code is the items in the list not the list itself:

public class MatchItem : IEquatable<MatchItem>
{
    public int SomeInt { get; set; }
    public decimal SomeDecimal {get; set; }

    public bool Equals(MatchItem item)
    {
        if(item == null)
            return false;

        return this.SomeInt == item.SomeInt && this.SomeDecimal == item.SomeDecimal;
    }

    // You should also override object.ToString, object.Equals & object.GetHashCode. 
    // Omitted for brevity here!
}

You'll note that has an implementation of IEquatable<MatchItem> which allows it to be compared to other instances of MatchItem .

Thereafter, this code will work:

var items = new List<MatchItem>()
{
    new MatchItem{SomeInt = 1, SomeDecimal = 0.3M},
    new MatchItem{SomeInt = 12, SomeDecimal = 2.3M}
};

var searchItem = new MatchItem{SomeInt = 1, SomeDecimal = 0.3M};

Console.WriteLine(items.Contains(searchItem)); // true

Working example: http://rextester.com/ZWNC6890

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