0

I have the next class:

public class MapsDescModel : NotificationObject, IEqualityComparer<MapsDescModel>
{
    public MapsDescModel(ObservableCollection<MainCategories> mainCategoty)
    {
        MainCategories = mainCategoty;
    }

    private MainCategories _mainCategorySelectedItem;
    public MainCategories MainCategorySelectedItem
    {
        get { return _mainCategorySelectedItem; }
        set
        {
            if (Equals(value, _mainCategorySelectedItem)) return;
            _mainCategorySelectedItem = value;
            RaisePropertyChanged("MainCategorySelectedItem");
            RaisePropertyChanged("SubCategories");
        }
    }

    private SubCategories _subCategorySelectedItem;
    public SubCategories SubCategorySelectedItem
    {
        get { return _subCategorySelectedItem; }
        set
        {
            if (Equals(value, _subCategorySelectedItem)) return;
            _subCategorySelectedItem = value;
            RaisePropertyChanged("SubCategorySelectedItem");
        }
    }

    private ObservableCollection<MainCategories> _mainCategories;
    public ObservableCollection<MainCategories> MainCategories
    {
        get { return _mainCategories; }
        set
        {
            if (Equals(value, _mainCategories)) return;
            _mainCategories = value;
            RaisePropertyChanged("MainCategories");
        }
    }

    public ObservableCollection<SubCategories> SubCategories
    {
        get
        {
            if (MainCategorySelectedItem != null)
                return
                    Infrastructure.Helpers.ExtensionMethods.ToObservableCollection(
                        MainCategorySelectedItem.SubCategory.AsEnumerable());
            else return new ObservableCollection<SubCategories>();
        }
    }


    public bool Equals(MapsDescModel x, MapsDescModel y)
    {
        return
            x.MainCategorySelectedItem.MainCatID == y.MainCategorySelectedItem.MainCatID &&
            x.SubCategorySelectedItem.SubCatID == y.SubCategorySelectedItem.SubCatID;
    }

    public int GetHashCode(MapsDescModel obj)
    {
        if (Object.ReferenceEquals(obj, null)) return 0;

        if (obj.MainCategorySelectedItem == null || obj.SubCategorySelectedItem == null) 
            return 0;
        else  return obj.MainCategorySelectedItem.Category.GetHashCode() + obj.SubCategorySelectedItem.Category.GetHashCode();
    }
}

And i have the next collection in other class:

MapsGrid = new ObservableCollection<MapsDescModel>()

I'm trying to use MapGrid.Distinct() method but it not working as it should.

The properties MainCatID and SubCatID are Integers. When I'm inserting 2 objects with same properties values to the collection and use Distinct method nothing happens. I check by code (Console.WriteLine(MapsGrid[0].Equals(MapsGrid[1]));) what the comparison returns and it returns false even the properties are equal. Where is my mistake?


Update:

I edited MapsDescModel class:

  public class MapsDescModel : NotificationObject, IEqualityComparer<MapsDescModel>, IEquatable<MapsDescModel>
    {
        public MapsDescModel(ObservableCollection<MainCategories> mainCategoty)
        {
            MainCategories = mainCategoty;

        }



        private MainCategories _mainCategorySelectedItem;
        public MainCategories MainCategorySelectedItem
        {
            get { return _mainCategorySelectedItem; }
            set
            {
                if (Equals(value, _mainCategorySelectedItem)) return;
                _mainCategorySelectedItem = value;
                RaisePropertyChanged("MainCategorySelectedItem");
                RaisePropertyChanged("SubCategories");
            }
        }

        private SubCategories _subCategorySelectedItem;
        public SubCategories SubCategorySelectedItem
        {
            get { return _subCategorySelectedItem; }
            set
            {
                if (Equals(value, _subCategorySelectedItem)) return;
                _subCategorySelectedItem = value;
                RaisePropertyChanged("SubCategorySelectedItem");
            }
        }


        private ObservableCollection<MainCategories> _mainCategories;
        public ObservableCollection<MainCategories> MainCategories
        {
            get { return _mainCategories; }
            set
            {
                if (Equals(value, _mainCategories)) return;
                _mainCategories = value;
                RaisePropertyChanged("MainCategories");
            }
        }

        public ObservableCollection<SubCategories> SubCategories
        {
            get
            {
                if (MainCategorySelectedItem != null)
                    return
                        Infrastructure.Helpers.ExtensionMethods.ToObservableCollection(
                            MainCategorySelectedItem.SubCategory.AsEnumerable());
                else return new ObservableCollection<SubCategories>();
            }
        }


        public bool Equals(MapsDescModel x, MapsDescModel y)
        {
            if (x.MainCategorySelectedItem == null || x.SubCategorySelectedItem == null ||
                y.MainCategorySelectedItem == null || y.SubCategorySelectedItem == null)
                return false;

            return
                x.MainCategorySelectedItem.MainCatID == y.MainCategorySelectedItem.MainCatID &&
                x.SubCategorySelectedItem.SubCatID == y.SubCategorySelectedItem.SubCatID;
        }

        public int GetHashCode(MapsDescModel obj)
        {
            if (Object.ReferenceEquals(obj, null)) return 0;

            if (obj.MainCategorySelectedItem == null || obj.SubCategorySelectedItem == null)
                return 0;
            else return obj.MainCategorySelectedItem.Category.GetHashCode() + obj.SubCategorySelectedItem.Category.GetHashCode();
        }

        public bool Equals(MapsDescModel other)
        {
            return
            this.Equals(this, other);  // use definition from IEqualityComparer<T>
        }

        public override bool Equals(object obj)
        {
            MapsDescModel other = obj as MapsDescModel;
            if (other == null)
                return base.Equals(obj);
            else
                return this.Equals(other);
        }

        public override int GetHashCode()
        {
            MapsDescModel other = this as MapsDescModel;
            if (other == null)
                return base.GetHashCode();
            else
                return this.GetHashCode(other);
        }

and now when I executing Distinct method it still not working. I know that my Equality method is working because the line 'Console.WriteLine(MapsGrid[0].Equals(MapsGrid[1]));' returns true.

Any ideas?

Ofir
  • 5,049
  • 5
  • 36
  • 61
  • 1
    I may be saying nonsense, but maybe you need to put `override` keyword before `bool Equals` and `int GetHashCode` ? – Conrad Clark Apr 09 '13 at 16:10
  • no this cant be the problem. the methods signature are different than Object methods (notice that those methods get MapDescModel parameter as input) – Ofir Apr 09 '13 at 16:14
  • @ConradClark - no, the OP is implementing `IEqualityComparer`, not overriding the `object` methods. – D Stanley Apr 09 '13 at 16:16
  • Yeah sorry, I overlooked that. – Conrad Clark Apr 09 '13 at 16:17
  • `Equals` should also accept one parameter, and `GetHashCode` should accept no parameter. – tia Apr 09 '13 at 16:22
  • @tia not in an [`IEqualityComparer`](http://msdn.microsoft.com/en-us/library/ms132151.aspx) implementation. – D Stanley Apr 09 '13 at 16:25
  • @DStanley Yes the OP is implementing that and it's wrong. OP should either implement `IEquatable<>` or just override `Equals` and `GetHashCode`. – tia Apr 09 '13 at 16:29
  • Define "MapGrid.Distinct() method is not working as it should". So Console.WriteLine(MapsGrid[0].Equals(MapsGrid[1]));' returns true. Does override bool Equals(object obj) get called and what does it return. This is just messed up. Why would you base the equality of two objects on the value of a MainCategorySelectedItem. Two object could be equal then you change a selected item and they are not equal? – paparazzo Apr 09 '13 at 16:54
  • I have a datagrid and each row contains 2 ComboBoxes - main category combo and sub category combo. I want to confirm at end of "adding rows process" that there are no duplicates. The value MainCategorySelectedItem and SubCategorySelectedItem save what the users chose. I checked with the debugger their values and they are equal – Ofir Apr 09 '13 at 17:00
  • Define "MapGrid.Distinct() method is not working as it should". Does override bool Equals(object obj) get called and what does it return? – paparazzo Apr 09 '13 at 17:28
  • "MapGrid.Distinct() method is not working as it should" - Not remove duplicates. It seems that override equales called many times (every screen vallidation - i think it because MapsGrid collection is bind to my data grid) but the first equals after adding new row returns "True". I have a direction - somthing with my equals methods is wrong. I changed all equals to "return true" and distinct works. I will report here – Ofir Apr 09 '13 at 17:57
  • My equals method return wrong result when one of the parameter was null. Thanks for the help of everyone – Ofir Apr 09 '13 at 18:14

2 Answers2

1

You've implemented IEqualityComparer<T>, which is fine if you want to pass in an instance of your class to Distinct:

var distinctList = MapGrid.Distinct(new MapsDescModel());

However a cleaner method is to implement IEquatable<T> instead, since Distinct will use that by default if you don't pass in an IEqualityComparer<T>:

public class MapsDescModel : NotificationObject, IEqualityComparer<MapsDescModel>, IEquatable<MapsDescModel>
{
...
    public bool Equals(MapsDescModel y)
    {
        return
            this.Equals(this,y);  // use definition from IEqualityComparer<T>
    }  
}

I would also recommend overriding object.Equals and object.GetHashCode for consistency, again leveraging the IEqualityComparer methods if you like (or just converting the IEqualityComparer methods to overrides if you decide you don't need them anymore).

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • I did it, now the equality method returns true but the distinct still not working - see my update above – Ofir Apr 09 '13 at 16:39
1

If you want help then answer the questions asked.

Does override bool Equals(object obj) get called and what does it return?
Your response failed to answer that very critical question.

Since you don't implement Object I suspect those OverRides are not called

Implementing the Equals Method

You are applying IEqualityComparer to a class (MapsDescModel) and it applies to a collection

IEqualityComparer Interface

I think what you need to do (or mean to do) is OverRide GetHashCode and Equals on the class MainCategories
But you don't post the definition for MainCategories
And I find the plur (s) interesting -- is

public ObservableCollection<MainCategories> MainCategories 

a collection of a collection?
Consider not naming a property the name of the class for clarity

paparazzo
  • 44,497
  • 23
  • 105
  • 176
  • i didn`t override anything in MainCategories. please notice that in my equals method I'm comparing just Integers. I got yor comment about the naming - you right – Ofir Apr 09 '13 at 16:49