Martin Martin - 2 months ago 10
C# Question

C# Copy inheritance hierarchy into string/enum format

In my game I have merchants. All items have a standard price. Each merchant has an interpretation of this price. I have an item inheritance hierarchy.

ConsumableItem
and
EquipableItem
inherits from the base class
GameItem
, HoldableEquipableItem inherits from EquipableItem and so on. A merchant can add a multiplier to one of these types, so if he has a multiplier of 0.5 on EquipableItem it means EquipableItem and all types inheriting from it will have their price multiplied with 0.5 (halved).

The inheritance hierarchy fits my problem since it doesn't have to be retyped anywhere and the tool
Type.IsSubclassOf
is built in available.But I'm not too fond of using types for game mechanics mainly because I want to show the type in the Unity inspector and it doesn't support Type, so I would have to use a string to symbolize it and parse the type afterward (maybe also 'ethical' and performance issues?).

Is there a good way I could implement this with a string or
enum
type instead of Type? A class where you had a method similar to
IsSubclassOf
just using string/enum instead. The type of the item could either be reflected through a field/property, or just convert
GetType
in the hierarchy to the string/enum version.

Answer

I forgot to post this. Here is my solution to the problem if anyone needs it.

/// <summary>
/// Mimics the Type inheritance hierarchy for enums
/// </summary>
// Enum is a special class that cannot be used as a constraint, so instead use its parent interface IConvertible
public class InheritanceHierarchy<T> where T : IConvertible
{
    private Dictionary<T, InheritanceElement<T>> elements =
        new Dictionary<T, InheritanceElement<T>>();

    public void Add(T element, T parent)
    {
        var parentElement = parent.Equals(default(T)) ? null : elements[parent];
        elements.Add(element, new InheritanceElement<T>(element, parentElement));
    }

    /// <summary>
    /// Add parent for multiple children
    /// </summary>
    public void Add(T parent, params T[] elements)
    {
        foreach (var element in elements)
            Add(element, parent);
    }

    public bool IsSameOrSubclass(T element, T parent)
    {
        return ParentIndex(element, parent) != -1;
    }

    /// <summary>
    /// Get how many parents the element is from parent. If they don't relate return -1
    /// </summary>
    public int ParentIndex(T element, T parent)
    {
        // If the element is same as parent
        if (element.Equals(parent))
            return 0;
        // Loop through the chain of parents checking until it is either null or a match
        var actualParent = elements[element].parent;
        var parentIndex = 1;
        while (actualParent != null)
        {
            if (parent.Equals(actualParent.element))
                return parentIndex;
            else
            {
                actualParent = actualParent.parent;
                parentIndex++;
            }
        }
        return -1;
    }
}

public class InheritanceElement<T> where T : IConvertible
{
    public T element;
    public InheritanceElement<T> parent;

    public InheritanceElement(T element, InheritanceElement<T> parent)
    {
        this.element = element;
        this.parent = parent;
    }
}