Q:

How to Create Two level enum

Sorry if the question's title is confusing,but i don't know how to ask it.
what is really want is to have read-only data that will never change.
currently i have two enums MeterType and SubMeterType
public enum MeterType
{
  Water = 1001,
  Electricity = 1004,
  Gas = 1007
}

and
public enum SubMeterType
{
  DrinkingWater = 1002,
  UsageWater = 1003,
  SubsidiseGas = 1008,
  NonSusbsidisedGas = 1009
} 

Now i would like to use these as follows
To get the MeterType
string meterType = MeterType.Water.ToString("d");

and to get the SubMeterType, is it possible to have something like
string subMeterType = MeterType.Water.DrinkingWater("d");

Shall go for another approach using classes with readonly properties ?
or modify these enums to suit my requirement.

A:

Instead of using enums you might use constant integers in nested classes:
public static class MeterType
{
    public const int Water = 1001;
    public const int Electricity = 1004;
    public const int Gas = 1007;

    public static class Waters
    {
        public const int DrinkingWater = 1002;
        public const int UsageWater = 1003;
    }

    public static class Gases
    {
        public const int SubsidiseGas = 1008;
        public const int NonSusbsidisedGas = 1009;
    }
}

A:

Just use a nested enum:
public class MeterType
{
    public enum Water { }
}

But in this case you can't use MeterType.Water directly, this is not possible by default. Try use nested objects then or a secondary enum for the MeterType.
public enum MeterType { }
public enum MeterTypeWater { }

In this case you need a property with a different name for each of the enums. Best solution is to not use a nested class:
public class MeterType
{
    public static WaterType Water { get; }
}

public class WaterType
{
    public readonly SubWaterType DrinkingWater = SubWaterType.DrinkingWater;
}

A:

You cannot nest enums but you already know that. What you can do is to have const or readonly properties/fields which map to the various types you want. Then in each of the types, you define fields/properties for the subtypes.
public static class MeterTypes
{
    public static readonly Electricity electricity;
    public static readonly Gas gas;
    public static readonly Water water;

    static MeterTypes()
    {
        // initialize the meter types to their default
        MeterTypes.Water = Water.GenericWater;
        MeterTypes.Gas = Gas.GenericGas;
        MeterTypes.Electricity = Electricity.GenericElectricity;
    }

    private MeterTypes()
    {
        // private initialization prevents others from creating the class            
    }

    public class Electricity
    {
        public enum Type
        {
            Generic = 1007,
            SubsidisedElectricity = 1008,
            NonSubsidisedElectricity = 1009
        }

        public static readonly Electricity GenericElectricity;
        public static readonly Electricity SubsidisedElectricity;
        public static readonly Electricity NonSubsidisedElectricity;
        private Type ElectricityType;

        static Electricity()
        {
            SubsidisedElectricity = new Electricity(Type.SubsidisedElectricity);
            NonSubsidisedElectricity = new Electricity(Type.NonSubsidisedElectricity);
            GenericElectricity = new Electricity(Type.Generic);
        }

        // private constructor prevents creation from outside the class
        private Electricity(Type ElectricityType)
        {
            this.ElectricityType = ElectricityType;
        }

        public override string ToString()
        {
            return ElectricityType.ToString();
        }

        public string ToString(string format)
        {
            return ElectricityType.ToString(format);
        }
    }

    public class Gas
    {
        public enum Type
        {
            Generic = 1007,
            SubsidisedGas = 1008,
            NonSubsidisedGas = 1009
        }

        public static readonly Gas GenericGas;
        public static readonly Gas SubsidisedGas;
        public static readonly Gas NonSubsidisedGas;
        private Type gasType;

        static Gas()
        {
            SubsidisedGas = new Gas(Type.SubsidisedGas);
            NonSubsidisedGas = new Gas(Type.NonSubsidisedGas);
            GenericGas = new Gas(Type.Generic);
        }

        // private constructor prevents creation from outside the class
        private Gas(Type gasType)
        {
            this.gasType = gasType;
        }

        public override string ToString()
        {
            return gasType.ToString();
        }

        public string ToString(string format)
        {
            return gasType.ToString(format);
        }
    }

    public class Water
    {
        public enum Type
        {
            Generic = 1001,
            DrinkingWater = 1002,
            UsageWater = 1003
        }

        public static readonly Water GenericWater;
        public static readonly Water DrinkingWater;
        public static readonly Water UsageWater;
        private Type waterType;

        static Water()
        {
            DrinkingWater = new Water(Type.DrinkingWater);
            UsageWater = new Water(Type.UsageWater);
            GenericWater = new Water(Type.Generic);
        }

        // private constructor prevents creation from outside the class
        private Water(Type waterType)
        {
            this.waterType = waterType;
        }

        public override string ToString()
        {
            return waterType.ToString();
        }

        public string ToString(string format)
        {
            return waterType.ToString(format);
        }
    }
}

This can be used as such
var w = MeterTypes.water; // will give generic water
var uw = MeterTypes.Water.UsageWater // will give usage water

and you get the added use of the Enum.ToString() methods too.
You'll have to note that this implementation relies on C#'s case sensitivity. This makes MeterTypes.electricity and MeterTypes.Electricity refer to a field and a class respectively. This code will is very likely to fail if it ever gets used in a language that is not case sensitive (e.g. VB.NET). You could circumvent this by using a different name for the static fields in the MeterTypes class (e.g. _Electricity instead of electricity).

