Click here to Skip to main content
15,884,629 members
Articles / Programming Languages / C#

How To Safely Convert Enums

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
17 Jul 2014LGPL31 min read 5.7K   2  
How to safely convert enums

Converting between different types of enums is quite easy and it typically works fine. For a while. But changed business requirements might require that you modify the enums, and it’s easy to forget a conversion somewhere.

So let’s say that you got these enums:

C#
//domain enum
public enum AccountState
{
    NotActivated,
    Active,
    RequiresReActivation
}

//DTO enum
public enum QueryAccountState
{
    NotActivated,
    Active,
    RequiresReActivation
}

A conversion is straight forward:

C#
class Program
{
    static void Main(string[] args)
    {
        var queryState = (QueryAccountState) AccountState.Locked;
        Console.WriteLine(queryState);
    }
}

However, if you later introduce a new state in the domain model:

C#
public enum AccountState
{
    NotActivated,
    Active,
    RequiresReActivation,
    Locked // <--- new state
}

... and forget that in the QueryAccountState your code will still work fine:

C#
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("domain: " + AccountState.Locked);
        Console.WriteLine("DTO:    "+  (QueryAccountState)AccountState.Locked);
    }
}

The problem is that the code will still compile and return zero errors.

screenshot

The queryState variable will contain the value three and any comparison with the QueryAccountState enum will silently fail (due to the fact that the value is not a part of the enum).

Here is a simple test:

C#
public enum AccountState
{
    NotActivated,
    Active,
    RequiresReActivation,
    Locked
}

public enum QueryAccountState
{
    NotActivated,
    Active,
    RequiresReActivation,
}

class Program
{
    static void Main(string[] args)
    {
        var queryState = (QueryAccountState) AccountState.Locked;
        if (queryState == QueryAccountState.Active)
            Console.WriteLine("Active");
        if (queryState == QueryAccountState.NotActivated)
            Console.WriteLine("NotActivated");
        if (queryState == QueryAccountState.RequiresReActivation)
            Console.WriteLine("RequiresReActivation");
    }
}

... that code will print nothing.

Using String Conversion

A more solid approach is to convert the value to a string and then let the enum parse the string:

C#
class Program
{
    static void Main(string[] args)
    {
        var domainState = AccountState.Locked;

        QueryAccountState queryState;
        if (!Enum.TryParse(domainState.ToString(), out queryState))
            throw new FormatException("Value '" + domainState + "' 
                                       do not exist in the QueryAccountState enum.");
    }
}

Result:

screenshot2

Enums with Different Value Names

Sometimes, you have enums that have different value names. You typically convert them using a switch statement:

C#
private LastTriggerAction ConvertLastAction(Api.Triggers.Commands.LastTriggerAction lastTriggerAction)
{
    switch (lastTriggerAction)
    {
        case Api.Triggers.Commands.LastTriggerAction.AbortTrigger:
            return LastTriggerAction.Revoke;
        case Api.Triggers.Commands.LastTriggerAction.ExecuteActions:
            return LastTriggerAction.Grant;
    }
}

However, do not forget to add a default statement to catch differences:

C#
private LastTriggerAction ConvertLastAction(Api.Triggers.Commands.LastTriggerAction lastTriggerAction)
{
    switch (lastTriggerAction)
    {
        case Api.Triggers.Commands.LastTriggerAction.AbortTrigger:
            return LastTriggerAction.Revoke;
        case Api.Triggers.Commands.LastTriggerAction.ExecuteActions:
            return LastTriggerAction.Grant;
        default:
            throw new FormatException("Value '" + lastTriggerAction + "' 
                                       do not exist in the LastTriggerAction enum.");
    }
}

Summary

So if you are doing enum conversions, try to use string conversions or switch statements with a default option to be sure that the application will not stop working in future versions.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Founder 1TCompany AB
Sweden Sweden

Comments and Discussions

 
-- There are no messages in this forum --