Matt Gregory
Matt Gregory

Reputation: 8662

Union of two ObservableCollections returns duplicates

I am trying to derive the union of two ObservableCollections and the items in the union are not unique.

using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;

namespace ObservableCollectionUnion
{
    class Program
    {
        class Option { public string Code; }

        static void Main(string[] args)
        {
            Option[] opts1 = {
                new Option { Code = "1" },
                new Option { Code = "2" },
            };
            Option[] opts2 = {
                new Option { Code = "2" },
                new Option { Code = "3" },
            };
            ObservableCollection<Option> obsOpts1 = new ObservableCollection<Option>(opts1);
            ObservableCollection<Option> obsOpts2 = new ObservableCollection<Option>(opts2);
            ObservableCollection<Option> obsOptsBoth = new ObservableCollection<Option>(obsOpts1.Union(obsOpts2));

            foreach (Option opt in obsOptsBoth) {
                Debug.WriteLine(opt.Code);
            }
        }
    }
}

The output is:

1
2
2
3

How do I get 1,2,3? I've tried passing in an IComparer or an IEqualityComparer, but I get the error

Error   CS1929  'ObservableCollection<Program.Option>' does not contain a definition for 'Union' and the best extension method overload 'Queryable.Union<Program.Option>(IQueryable<Program.Option>, IEnumerable<Program.Option>, IEqualityComparer<Program.Option>)' requires a receiver of type 'IQueryable<Program.Option>'

Here is what I'm trying to do with that:

using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;

namespace ObservableCollectionUnion
{
    class Program
    {
        class Option { public string Code; }

        class OptionComparer : IEqualityComparer
        {
            public new bool Equals(object x, object y)
            {
                return Convert.ToInt32(((Option)x).Code) == Convert.ToInt32(((Option)y).Code);
            }

            public int GetHashCode(object obj)
            {
                return ((Option)obj).Code.GetHashCode();
            }
        }

        static void Main(string[] args)
        {
            Option[] opts1 = {
                new Option { Code = "1" },
                new Option { Code = "2" },
            };
            Option[] opts2 = {
                new Option { Code = "2" },
                new Option { Code = "3" },
            };
            ObservableCollection<Option> obsOpts1 = new ObservableCollection<Option>(opts1);
            ObservableCollection<Option> obsOpts2 = new ObservableCollection<Option>(opts2);
            ObservableCollection<Option> obsOptsBoth = new ObservableCollection<Option>(obsOpts1.Union(obsOpts2, new OptionComparer()));

            foreach (Option opt in obsOptsBoth) {
                Debug.WriteLine(opt.Code);
            }
        }
    }
}

The funny thing is that I'm following what the intellisense is telling me. It says ObservableCollection.Union has a signature of

    public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer);

Upvotes: 0

Views: 44

Answers (1)

Ivan I
Ivan I

Reputation: 9990

It won't return duplicates. If you did something like

var commonOption = new Option { Code = "2" }

and used it in the observable collections it would work as expected. By default classes are equal only if they are the same instance. If you want some other sort of equality you may define it by overriding the equality operator.

Upvotes: 1

Related Questions