Reputation: 65
I'm trying to write an Equivalence function for my baseClass and subClasses. By "Equivalence" I mean that I want to check that all (or some) of the attributes of the compared instances are equal/equivalent.
My problem comes when I have a List of the base class and I want to check which elements have an equivalent match in the list.
Let's say the base class is called "Item". And the subclasses are "WeaponItem", "ConsumableItem", "EquipableItem", "ArmorItem", etc.. (Any number of subclasses with any number of depth of inheritance).
if I have an item list, I can only check the equivalence at the Item class level even though the instances could be of any of the subclasses.
My problem is that the equivalence at the base level gives me a different result than the equivalence a specific level:
List<Item> itemList = new List<Item>();
WeaponItem weaponItem1 = new WeaponItem();
weaponItem1.strength = 1;
WeaponItem weaponItem2 = new WeaponItem();
weaponItem2.strength = 5;
WeaponItem weaponItem3 = new WeaponItem();
weaponItem3.strength = 5;
weaponItem1.IsEquivalent(weaponItem2);//returns false
weaponItem2.IsEquivalent(weaponItem3);//returns true
itemList.Add(weaponItem1);
itemList.Add(weaponItem2);
itemList[0].IsEquivalent(itemList[1]);//returns true
(itemList[0] as WeaponItem).IsEquivalent((WeaponItem)itemList[1]);//returns false
The IsEquivalent function in Item only checks one thing. While the IsEquivalent function in WeaponItem checks all the attributes in the WeaponItem class.
So my question is how can I call the correct IsEquivalent function for any of the items in the List when I cannot cast the actual type because it could be any subclass of Item?
So in the example code above I would like to change the before-last line in a way that it returns false or change how I implement the IsEquivalent function.
Thank you for taking the time to look into this.
EDIT: So the error was with how I implemented the IsEquivalence methods I wasn't overriding the base function... I guess I was tired. I'm assuming that if I was using IEquatable (Equals, ==, !=, GetHash) I would need it once for IEquatable<'Item> and then I would override these function for each subclass. There would be no need to add IEquatable<'WeaponItem> as well or am I wrong to think that?
Upvotes: 2
Views: 108
Reputation: 26926
What you are talking about is using on of the fundamental features of object-oriented programming: polymorphism.
Using polymorphism, calling IsEquivalent
on an object calls the version implemented in the that object's actual class, and not the one in base class it is being referenced by.
So, here is an implementation:
public abstract class Item {
public virtual bool IsEquivalent(Item i2) {
return true;
}
}
public class WeaponItem : Item {
public int strength;
public override bool IsEquivalent(Item i2) {
var ans = base.IsEquivalent(i2);
if (i2 is WeaponItem w2)
ans = ans && strength == w2.strength;
return ans;
}
}
NOTE: If your equivalence can be more complex than just the two cases of Item
vs Item
when the two actual types are different, or SameType vs SameType (e.g. WeaponItem
vs WeaponItem
) when they are the same, you will need to use double-dispatch polymorphism to capture the first type and then delegate equivalency testing to the second Item
to avoid type testing in each IsEquivalent
. You could also use dynamic
for double-dispatch if you don't mind the performance hit.
Upvotes: 3