あとで

なんか急に思いついて書いてみた。めもめも。

public abstract class BasicTypeSafeEnum<T> where T : BasicTypeSafeEnum<T>
{
    string name;

    public string Name
    {
        get
        {
            FieldInfo[] fields = typeof(T).GetFields(
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
            foreach (FieldInfo field in fields)
            {
                if (field.GetValue(null) == this)
                {
                    name = field.Name;
                    return name;
                }
            }
            name = "";
            return name;
        }
    }

    public override string ToString()
    {
        return Name;
    }
}

public abstract class OrderedTypeSafeEnum<T>
    : BasicTypeSafeEnum<T>, IComparable<T>, IComparable where T : OrderedTypeSafeEnum<T>
{
    static int crnt = 0;

    public readonly int Ordered = crnt++;

    public int CompareTo(T other)
    {
        return crnt.CompareTo(other.Ordered);
    }

    public int CompareTo(object obj)
    {
        return crnt.CompareTo(((T)obj).Ordered);
    }
}

public abstract class ListedTypeSafeEnum<T> : OrderedTypeSafeEnum<T> where T : ListedTypeSafeEnum<T>
{
    List<T> items = new List<T>();

    protected ListedTypeSafeEnum()
    {
        items.Add((T)this);
    }

    public IList<T> Items
    {
        get
        {
            return new ReadOnlyCollection<T>(items);
        }
    }
}

public abstract class MappedTypeSafeEnum<T> : ListedTypeSafeEnum<T> where T : MappedTypeSafeEnum<T>
{
    static Dictionary<string, T> map = new Dictionary<string, T>();

    public static T ValueOf(string name)
    {
        if (map.ContainsKey(name))
            return map[name];

        FieldInfo[] fields = typeof(T).GetFields(
            BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
        foreach (FieldInfo field in fields)
        {
            if (field.Name == name)
            {
                T item = field.GetValue(null) as T;
                map.Add(name, item);
                return item;
            }
        }
        return null;
    }
}