9

The database I am working with currently has a varchar field, and in my code I want to map the potential values to a enumeration like:

public enum UserStatus
{
    Anonymous,
    Enrolled,
    SuperUser
}

At the database level for this column, there is a constrain on it where the value has to be:

ANONYMOUS
ENROLLED
SUPERUSER

Is it possible for me to do:

UserStatus.SuperUser.ToString()

And have that value be SUPERUSER, and this be consistant and not screw up down the road?

Cœur
  • 37,241
  • 25
  • 195
  • 267
loyalflow
  • 14,275
  • 27
  • 107
  • 168
  • 1
    If you are in control of the codebase, then for sure you can ensure that. – David Heffernan Dec 16 '13 at 20:16
  • 1
    [`ToUpperInvariant()`](http://msdn.microsoft.com/en-us/library/system.string.toupperinvariant(v=vs.110).aspx) ? – PoByBolek Dec 16 '13 at 20:16
  • 1
    You might not even need this. You don't specify your SQL dialect, but many of them are case-insensitive by default for text, meaning `'SuperUser'` would satisfy the constraint. –  Dec 16 '13 at 20:20

3 Answers3

7

A better solution may be to take advantage of the DescriptionAttribute:

public enum UserStatus
{
    [Description("ANONYMOUS")]
    Anonymous,
    [Description("ENROLLED")]
    Enrolled,
    [Description("SUPERUSER")]
    SuperUser
}

Then use something like:

/// <summary>
/// Class EnumExtenions
/// </summary>
public static class EnumExtenions
{
    /// <summary>
    /// Gets the description.
    /// </summary>
    /// <param name="e">The e.</param>
    /// <returns>String.</returns>
    public static String GetDescription(this Enum e)
    {
        String enumAsString = e.ToString();
        Type type = e.GetType();
        MemberInfo[] members = type.GetMember(enumAsString);
        if (members != null && members.Length > 0)
        {
            Object[] attributes = members[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
            if (attributes != null && attributes.Length > 0)
            {
                enumAsString = ((DescriptionAttribute)attributes[0]).Description;
            }
        }
        return enumAsString;
    }

    /// <summary>
    /// Gets an enum from its description.
    /// </summary>
    /// <typeparam name="TEnum">The type of the T enum.</typeparam>
    /// <param name="description">The description.</param>
    /// <returns>Matching enum value.</returns>
    /// <exception cref="System.InvalidOperationException"></exception>
    public static TEnum GetFromDescription<TEnum>(String description)
        where TEnum : struct, IConvertible // http://stackoverflow.com/a/79903/298053
    {
        if (!typeof(TEnum).IsEnum)
        {
            throw new InvalidOperationException();
        }
        foreach (FieldInfo field in typeof(TEnum).GetFields())
        {
            DescriptionAttribute attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
            if (attribute != null)
            {
                if (attribute.Description == description)
                {
                    return (TEnum)field.GetValue(null);
                }
            }
            else
            {
                if (field.Name == description)
                {
                    return (TEnum)field.GetValue(null);
                }
            }
        }
        return default(TEnum);
    }
}

So now you're referencing UserStatus.Anonymous.GetDescription().

Of course you could always make your own DatabaseMapAttribute (or what-have-you) and create your own extension methods. Then you can kill a reference to System.ComponentModel. Completely your call.

Brad Christie
  • 100,477
  • 16
  • 156
  • 200
  • If you define it as `GetDescription()`, you have to call it as `GetDescription()` too, not as `ToDescription()` :) –  Dec 16 '13 at 20:23
  • @hvd: Good call. Still getting through a Monday. ;-) – Brad Christie Dec 16 '13 at 20:24
  • 2
    Is this really better? Judging from the amount of code you'd have to maintain I'd prefer Habib's solution... – PoByBolek Dec 16 '13 at 20:24
  • 1
    @PoByBolek One major advantage is that it will support strings that are not valid as C# identifiers. –  Dec 16 '13 at 20:25
  • @PoByBolek You wouldn't really have to maintain it as it is rather trivial code, more so due to the Generic part. – Silvermind Dec 16 '13 at 20:25
  • @PoByBolek: I guess it depends. As-is, it probably isn't any better. But if you did take it the extra step and made the methods more concise (e.g `ToDatabaseEnum`) it may be more readable. Also, this would be fine to work with spaces (if that ever became a concern). – Brad Christie Dec 16 '13 at 20:26
  • 1
    Sure... But the OP's constraint was that the value has to be one of `ANONYMOUS`, `ENROLLED` or `SUPERUSER`. Just saying... ;) – PoByBolek Dec 16 '13 at 20:29
  • It might be useful to support something like `EnumMemberAttribute` - at least it will make the transformation consistent with DCS. – user2864740 Dec 17 '13 at 00:07
6

You can't override ToString for enums, instead you can create your own Extension Method like:

public static class MyExtensions
{
    public static string ToUpperString(this UserStatus userStatus)
    {
        return userStatus.ToString().ToUpper();// OR .ToUpperInvariant 
    }
}

And then call it like:

string str = UserStatus.Anonymous.ToUpperString();
Habib
  • 219,104
  • 29
  • 407
  • 436
  • @user1361315, it is for culture-insensitive conversion to upper case. see [this](http://msdn.microsoft.com/en-us/library/system.string.toupperinvariant(v=vs.110).aspx) – Habib Dec 16 '13 at 20:37
  • Well I don't care about culture, it is just for the database so it shouldn't change by culture anyhow. So use ToUpperInvariant then? – loyalflow Dec 16 '13 at 20:57
  • @user1361315, if culture is not an issue then you can use `ToUpper`. – Habib Dec 16 '13 at 21:00
1

Enum.ToString supports 4 different formats. I'd go for:

UserStatus.SuperUser.ToString("G").ToUpper();

"G" ensures that it will try first to get the string representation of your enum.

Mauro2
  • 1,235
  • 1
  • 7
  • 9