2

I have several classes in my application, all of which have a Name property that I want to use as my basis for comparison (Distinct(), etc.). Since I am always going to be comparing on Name, I decided to extract an interface, ISomeComparedStuff, which simply has a Name propery that all my other classes implement. I set up a comparison class as such:

public class MyComparer : IEqualityComparer<ISomeComparedStuff>
{
     public bool Equals(ISomeComparedStuff x, ISomeComparedStuff y)
     {
          return x.Name == y.Name;
     }

     public int GetHashCode(ISomeComparedStuff obj)
     {
          return obj.Name.GetHashCode();
     }
}

The only problem is when I try to code against it:

public class SomeStuff : ISomeComparedStuff
{
  ...
}

public class SomeMoreStuff : ISomeComparedStuff
{
  ...
}

var someStuff = GetSomeStuff().Distinct(new MyComparer);
var someMoreStuff = GetSomeMoreStuff().Distinct(new MyComparer);

I am getting a cast error (SomeStuff to ISomeComparedStuff). Is there some way to do this so I only need one compare class, otherwise I'd have to create one for every one of my classes (even though I am always going to compare on Name)?

Note: I understand this question "title" needs help. Any suggestions would be great.

Brian David Berman
  • 7,514
  • 26
  • 77
  • 144

2 Answers2

2

Not sure if this is a good solution or not, but how about making MyComparer a generic class?

public class MyComparer<T> : IEqualityComparer<T>
    where T: ISomeComparedStuff
{
     public bool Equals(T x, T y)
     {
      return x.Name == y.Name;
     }

     public int GetHashCode(T obj)
     {
      return obj.Name.GetHashCode();
     }
}

Downside is you have to new up an appropriate version:

var someStuff = GetSomeStuff().Distinct(new MyComparer<SomeStuff>());
var someMoreStuff = GetSomeMoreStuff().Distinct(new MyComparer<SomeMoreStuff>());

Expanding a bit, you could also make a new extension method like this:

public static IEnumerable<T> DistinctByName<T>(this IEnumerable<T> values)
    where T: ISomeComparedStuff
{
    return values.Distinct(new MyComparer<T>());
}
Chris Shaffer
  • 32,199
  • 5
  • 49
  • 61
0

Maybe something like:

var someStuff = GetSomeStuff().Cast<ISomeComparedStuff>().Distinct(new MyComparer);

Or use the non-generic IEqualityComparer.

Craig Stuntz
  • 125,891
  • 12
  • 252
  • 273
  • I like this approach (especially if it were encapsulated in another extension method, eg DistinctByName()), but you would have to cast the elements back to the original type otherwise the resulting `IEnumerable` is probably pretty useless. – Chris Shaffer Dec 30 '10 at 20:27
  • Yes. I would be concerned that I would lose all the data after the cast. – Brian David Berman Dec 30 '10 at 20:31
  • You don't lose any data. Casts to an interface aren't lossy. – Craig Stuntz Dec 30 '10 at 20:39
  • Not lossy, but like I said, you would have to upcast back to the original type otherwise you can't easily access the other data. – Chris Shaffer Dec 30 '10 at 20:40