C# enum typo correction

1k Views Asked by At

I am sure everyone made a typo somewhere during the development and realized it after it is released. Well, I am experiencing the same issue except this problem live in the Enum options.

I have a enum definition like below in C#

    public enum SlideShowZoomEffect
    {
        NoEffect,
        ZoomIn,
        ZoonOut
    }

Recently, after release of the product, we realize that there's a typo for ZoonOut (it should be ZoomOut). We want to change this but it is save into database as a string (so it is saved as ZoonOut) and program will reconstruct the enum by calling enum.parse(...) which allow us to use it in our program as an enum.

The problem here is that once we changed the ZoonOut to ZoomOut, is there any ways I can have backward compatible so that both (string)ZoonOut and (string)ZoomOut will be parsed as (enum)ZoomOut?

Any suggestion will be great!

Thank you


UPDATE (Solution to this issue):

With answer accepted below, here's my testing code to show the effect on this accepted solution for future reference purposes. Thank you all

class Program
{
    static void Main(string[] args)
    {
        //Testing input as (string)ZoomOut
        Console.WriteLine("Testing #1: Input String = 'ZoomOut'");
        TestCase("ZoomOut");
        Console.WriteLine("\n\n\n");


        //Testing input as (string)ZoonOut
        Console.WriteLine("Testing #2: Input String = 'ZoonOut'");
        TestCase("ZoonOut");
        Console.WriteLine("\n\n\n");


        //Additional testing to ensure the TestCase function is working, we should see something else detected here
        Console.WriteLine("Testing #3: Input String = 'ZoomIn'");
        TestCase("ZoomIn");
    }


    static void TestCase(string inputString)
    {
        SlideShowZoomEffect enumInput = (SlideShowZoomEffect)Enum.Parse(typeof(SlideShowZoomEffect), inputString);

        Console.WriteLine("enumInput.tostring() = " + enumInput.ToString());


        Console.WriteLine("\n===> using case SlideShowZoomEffect.ZoonOut:");
        switch (enumInput)
        {
            case SlideShowZoomEffect.ZoonOut:
                Console.WriteLine("      ===> ZoomOut detected");
                break;

            default:
                Console.WriteLine("      ===> Something else detected");
                break;
        }



        Console.WriteLine("\n===> using case SlideShowZoomEffect.ZoomOut:");
        switch (enumInput)
        {
            case SlideShowZoomEffect.ZoomOut:
                Console.WriteLine("      ===> ZoomOut detected");
                break;

            default:
                Console.WriteLine("      ===> Something else detected");
                break;
        }
    }


    public enum SlideShowZoomEffect
    {
        NoEffect,
        ZoomIn,
        ZoomOut,
        ZoonOut = ZoomOut
    }
}

Here's the output from console

Testing #1: Input String = 'ZoomOut'
enumInput.tostring() = ZoomOut

===> using case SlideShowZoomEffect.ZoonOut:
      ===> ZoomOut detected

===> using case SlideShowZoomEffect.ZoomOut:
      ===> ZoomOut detected




Testing #2: Input String = 'ZoonOut'
enumInput.tostring() = ZoomOut

===> using case SlideShowZoomEffect.ZoonOut:
      ===> ZoomOut detected

===> using case SlideShowZoomEffect.ZoomOut:
      ===> ZoomOut detected




Testing #3: Input String = 'ZoomIn'
enumInput.tostring() = ZoomIn

===> using case SlideShowZoomEffect.ZoonOut:
      ===> Something else detected

===> using case SlideShowZoomEffect.ZoomOut:
      ===> Something else detected
Press any key to continue . . .
4

There are 4 best solutions below

10
On BEST ANSWER

This should work:

  public enum SlideShowZoomEffect
    {
        NoEffect,
        ZoomIn,
        ZoomOut,
        ZoonOut = ZoomOut

    }

Edit: your safest bet would be to use @Bas' suggestion.

0
On

I believe that your best bet should be using attributes on enumeration values.

For example, you may implement an attribute SynonymAttribute:

public class SynonymAttribute : Attribute
{
    private readonly string _name;
    public SynonymAttribute(string name)
    {
        _name = name;
    }

    public string Name
    {
        get
        {
            return _name;
        }
    }
}

And then, you should use the SynonymAttribute whenever you want to map a synonym to some existing enumeration value:

public enum SlideShowZoomEffect 
{
     NoEffect,
     ZoomIn,

     [Synonym("ZoonOut")]
     ZoomOut
}

Finally, you can implement some helper method like this to workaround your situation:

public static class EnumHelper
{
    public static bool TryParse<TEnum>(string nameOrSynonym, out TEnum enumValue)where TEnum : struct
    {
        enumValue = default (TEnum);
        bool success = false;
        TEnum result;

        // First of all, this is the first attemp to parse the enum
        // value using regular Enum.TryParse. If it succeeds, it will mean
        // that passed enum value name is already in the enumeration. 
        if (!Enum.TryParse<TEnum>(nameOrSynonym, true, out result))
        {
            nameOrSynonym = nameOrSynonym.ToLowerInvariant();

            // If we need to look for a synonym of passed enumeration value
            // name, then we need reflection to look for static fields
            // in the given enumeration type. Enumeration values are just
            // static fields.

            // The SingleOrDefault part will look for fields with 
            // SynonymAttribute and it will extract the one with the
            // synonym which equals the passed enumeration value name!
            FieldInfo enumValueField = typeof (TEnum).GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.GetField)
                                                    .SingleOrDefault
                                                    (
                                                        field => field.GetCustomAttribute<SynonymAttribute>() != null 
                                                                && field.GetCustomAttribute<SynonymAttribute>().Name.ToLowerInvariant() == nameOrSynonym
                                                    );



            // If the synonym was found, then we get the field value
            // and we set it to the result enum value!
            if (enumValueField != null)
            {
                enumValue = (TEnum)enumValueField.GetValue(null);
                success = true;
            }
        }
        else
        {
            enumValue = result;
            success = true;
        }

        return success;
    }
}

Here's a sample usage of the EnumHelper.TryParse with synonym support:

    SlideShowZoomEffect enumValue;

    EnumHelper.TryParse<SlideShowZoomEffect>("ZoonOut", out enumValue);

    // This will output "ZoomOut"!
    Console.WriteLine("{0}", enumValue.ToString("f"));

Also, same sample in DotNetFiddle!

1
On

Alternative answer for Alioza's approach:

update TableX set MyEnumField = 'ZoomOut' where MyEnumField = 'ZoonOut'

Run it when you patch your product ;)

0
On

Try this one

public enum SlideShowZoomEffect
{
    NoEffect = 1,
    ZoomIn = 2,
    ZoonOut = 3,
    ZoomOut = 3
}

I tried it in simple console program. It shows they are identical.

class Program
{
    static void Main(string[] args)
    {
        bool result = (SlideShowZoomEffect.ZoonOut == SlideShowZoomEffect.ZoomOut); //True
        Console.WriteLine(result);
        Console.ReadLine();
    }
}