Working With SmartEnums In C#

Enum means enumeration i.e., mentioning things one by one, and enum type is a special data type that enables a variable to be a set of predefined constants.

Below is the sample which demonstrates a simple use of Enum in regular development.

public enum Vehicles {
    CAR,
    BIKE,
    VAN
}

Here in the above sample, we declared Vehicle enum where we have a set of vehicle types. Now, in our business logic, we can use these enum constants to represent vehicle type and get the constant name as well the integer value of the order (by default will start with 1).

Now if we need to get the average price of each vehicle type we may need to write a method as below by accepting vehicles enum as the input.

private static decimal GetAveragePrice(Vehicles vehicles) {
    switch (vehicles) {
        case Vehicles.CAR:
            return 10000;
        case Vehicles.BIKE:
            return 5000;
        case Vehicles.VAN:
            return 12000;
    }
    return default (decimal);
}

This method will return the average price of the given vehicle type. The same if we need to get average seat capacity, we need to write another similar method like GetSeatCapacity by input vehicle type and now we need to call these methods as follows.

Console.WriteLine($"Price for CAR {GetAveragePrice(Vehicles.CAR)}");
Console.WriteLine($"Price for BIKE {GetAveragePrice(Vehicles.BIKE)}");
Console.WriteLine($"Price for VAN {GetAveragePrice(Vehicles.VAN)}");

The output will be,

Can we get all such information about a vehicle type with its object? Yes, we can achieve this with a special implementation with the help of a tool called SmartEnums. We can install it from the NuGet package with the following command.

Install-Package Ardalis.SmartEnum -Version 2.0.1

Now, we modify the above functionality as follows using the SmartEnum package.

using Ardalis.SmartEnum;
public sealed class Vehicles: SmartEnum < Vehicles > {
    public static readonly Vehicles CAR = new Vehicles("CAR", 1, 10000, 5);
    public static readonly Vehicles BIKE = new Vehicles("BIKE", 2, 20000, 2);
    public static readonly Vehicles VAN = new Vehicles("VAN", 3, 30000, 12);
    public decimal Price {
        get;
        private set;
    }
    public int SeatCapacity {
        get;
        private set;
    }
    private Vehicles(string name, int value, decimal price, int seatCapacity): base(name, value) {
        Price = price;
        SeatCapacity = seatCapacity;
    }
}

Instead of Enum, we choose a sealed class and extended it from SmartEnum from Ardalis.SmartEnum namespace and need to pass our class name.

Now we have a constructor with minimum name and value variables and the rest we can have based on our requirement. In our case, we need both average price and seat capacity information for each vehicle type.

We declared static read-only variables with self-object creation by passing the respective values in the constructor.

Now on our business logic, we can call as follows,

Vehicles vehicle = Vehicles.CAR;
Console.WriteLine($"Price for Car {vehicle.Price}");
Console.WriteLine($"Price for Bike {Vehicles.BIKE.Price}");
Console.WriteLine($"Price for Van {Vehicles.FromName("VAN").Price}");
Console.WriteLine($"Seat Capacity for Car {vehicle.SeatCapacity}");
Console.WriteLine($"Seat Capacity for Bike {Vehicles.BIKE.SeatCapacity}");
Console.WriteLine($"Seat Capacity for Van {Vehicles.FromName("VAN").SeatCapacity}");

As observed, each console statement has different calling styles. One with vehicle variable and next directly calling from Enum type and last we used a special method called FromName.

SmartEnum class will accept name and value parameters via its constructor and it exposes two public methods FromName and FromValue.  Based on the given Name or Value, it will return the vehicle object and from there we can call our properties.

Now, we have no need for any extra methods on our business logic based on the enum type. If you have any requirement to implement huge functionality for each enum type. We can have the above vehicle class as an abstract class and inherit the required enum types as follows for more readability and future extendable classes.

using Ardalis.SmartEnum;
public abstract class Vehicles: SmartEnum < Vehicles > {
    public static readonly Vehicles CAR = new CARVehicle();
    public static readonly Vehicles BIKE = new BIKEVehicle();
    public static readonly Vehicles VAN = new VANVehicle();
    public decimal Price {
        get;
        private set;
    }
    public int SeatCapacity {
        get;
        private set;
    }
    public Vehicles(string name, int value, decimal price, int seatCapacity): base(name, value) {
        Price = price;
        SeatCapacity = seatCapacity;
    }
}
public sealed class CARVehicle: Vehicles {
    //Additional functionality can be implemented here
    public CARVehicle(): base("CAR", 1, 10000, 5) {}
}
public sealed class BIKEVehicle: Vehicles {
    //Additional functionality can be implemented here
    public BIKEVehicle(): base("BIKE", 2, 20000, 2) {}
}
public sealed class VANVehicle: Vehicles {
    //Additional functionality can be implemented here
    public VANVehicle(): base("VAN", 3, 30000, 12) {}
}

On business logic,

Vehicles vehicle = Vehicles.CAR;
Console.WriteLine($"Price for Car {vehicle.Price}");
Console.WriteLine($"Price for Bike {Vehicles.BIKE.Price}");
Console.WriteLine($"Price for Van {Vehicles.FromName("VAN").Price}");
Console.WriteLine($"Seat Capacity for Car {vehicle.SeatCapacity}");
Console.WriteLine($"Seat Capacity for Bike {Vehicles.BIKE.SeatCapacity}");
Console.WriteLine($"Seat Capacity for Van {Vehicles.FromName("VAN").SeatCapacity}");

Output as follows,

Thank you for the SmartEnum, now our code will be neater and more readable.

Happy Coding  ๐Ÿ™‚


Similar Articles