I would like to be able to compare two classes derived from the same abstract class in C#. The following code illustrates my problem.
I now I could fix the code by making BaseClass non abstract and then return a new BaseClass object in ToBassClass(). But isn’t there a more elegant and efficient solution?
abstract class BaseClass
{
BaseClass(int x)
{
X = x;
}
int X { get; private set; }
// It is probably not necessary to override Equals for such a simple class,
// but I've done it to illustrate my point.
override Equals(object other)
{
if (!other is BaseClass)
{
return false;
}
BaseClass otherBaseClass = (BaseClass)other;
return (otherBaseClass.X == this.X);
}
BaseClass ToBaseClass()
{
// The explicit is only included for clarity.
return (BaseClass)this;
}
}
class ClassA : BaseClass
{
ClassA(int x, int y)
: base (x)
{
Y = y;
}
int Y { get; private set; }
}
class ClassB : BaseClass
{
ClassB(int x, int z)
: base (x)
{
Z = z;
}
int Z { get; private set; }
}
var a = new A(1, 2);
var b = new B(1, 3);
// This fails because despite the call to ToBaseClass(), a and b are treated
// as ClassA and ClassB classes so the overridden Equals() is never called.
Assert.AreEqual(a.ToBaseClass(), b.ToBaseClass());
It depends on where exactly you want to test for equality. Clearly
ClassAandClassBinstances will never be “equal” in the real sense of that word, so overridingEqualsto behave like this might actually cause some weird bugs in your code.But if you want to compare them based on a specific criteria, then you can implement a specific IEqualityComparer (or several comparers) which suites your needs.
So, in this case you would have:
[Edit] Regarding comment:
Note that this doesn’t have anything with overriding the
Equalsmethod.But you will be able to check for equality like this:
This may not seem like a great thing at first, but it gives you several advantages:
a) You can have as many
IEqualityComparer<T>implementations as you want. Depending on the case, it may turn up that youEqualsoverride is not so great after all. Then you risk breaking all of your code depending on this.b) There are actually many classes which use
IEqualityComparer<T>to compare items.For example, you might want to use the
BaseClassas a key in a dictionary. In that case, you would use theDictionary<Key,Value>constructor overload which accepts anIEqualityComparer<T>:This way, dictionary will use the custom
ComparerByXduring key lookup.Also, for example, if you are using LINQ, you can check the Distinct() method example. It also supports an overload which returns distinct values, but compared using the specified custom
IEqualityComparer.