How to define an enum with string value?

C#StringEnums

C# Problem Overview


I am trying to define an Enum and add valid common separators which used in CSV or similar files. Then I am going to bind it to a ComboBox as a data source so whenever I add or remove from the Enum definition, I would not need to change anything in the combo box.

The problem is how can I define enum with string representation, something like:

public enum SeparatorChars{Comma = ",", Tab = "\t", Space = " "}

C# Solutions


Solution 1 - C#

You can't - enum values have to be integral values. You can either use attributes to associate a string value with each enum value, or in this case if every separator is a single character you could just use the char value:

enum Separator
{
    Comma = ',',
    Tab = '\t',
    Space = ' '
}

(EDIT: Just to clarify, you can't make char the underlying type of the enum, but you can use char constants to assign the integral value corresponding to each enum value. The underlying type of the above enum is int.)

Then an extension method if you need one:

public string ToSeparatorString(this Separator separator)
{
    // TODO: validation
    return ((char) separator).ToString();
}

Solution 2 - C#

You can achieve it but it will require a bit of work.

  1. Define an attribute class which will contain the string value for enum.

  2. Define an extension method which will return back the value from the attribute. Eg..GetStringValue(this Enum value) will return attribute value.

  3. Then you can define the enum like this..

    public enum Test : int {
        [StringValue("a")]
        Foo = 1,
        [StringValue("b")]
        Something = 2        
    } 
    
  4. To get back the value from Attribute Test.Foo.GetStringValue();

Refer : Enum With String Values In C#

Solution 3 - C#

As far as I know, you will not be allowed to assign string values to enum. What you can do is create a class with string constants in it.

public static class SeparatorChars
{
    public static String Comma { get { return ",";} } 
    public static String Tab { get { return "\t,";} } 
    public static String Space { get { return " ";} } 
}

Solution 4 - C#

For a simple enum of string values (or any other type):

public static class MyEnumClass
{
    public const string 
        MyValue1 = "My value 1",
        MyValue2 = "My value 2";
}

Usage: string MyValue = MyEnumClass.MyValue1;

Solution 5 - C#

You can't do this with enums, but you can do it like that:

public static class SeparatorChars
{
    public static string Comma = ",";

    public static string Tab = "\t";

    public static string Space = " ";
}

Solution 6 - C#

Maybe it's too late, but here it goes.

We can use the attribute EnumMember to manage Enum values.

public enum UnitOfMeasure
{
    [EnumMember(Value = "KM")]
    Kilometer,
    [EnumMember(Value = "MI")]
    Miles
}

This way the result value for UnitOfMeasure will be KM or MI. This also can be seen in Andrew Whitaker answer.

Solution 7 - C#

A class that emulates enum behaviour but using string instead of int can be created as follows...

public class GrainType
{
    private string _typeKeyWord;

    private GrainType(string typeKeyWord)
    {
        _typeKeyWord = typeKeyWord;
    }

    public override string ToString()
    {
        return _typeKeyWord;
    }

    public static GrainType Wheat = new GrainType("GT_WHEAT");
    public static GrainType Corn = new GrainType("GT_CORN");
    public static GrainType Rice = new GrainType("GT_RICE");
    public static GrainType Barley = new GrainType("GT_BARLEY");

}

Usage...

GrainType myGrain = GrainType.Wheat;

PrintGrainKeyword(myGrain);

then...

public void PrintGrainKeyword(GrainType grain) 
{
    Console.Writeline("My Grain code is " + grain.ToString());   // Displays "My Grain code is GT_WHEAT"
}

Solution 8 - C#

It is kind of late for answer, but maybe it helps someone in future. I found it easier to use struct for this kind of problem.

Following sample is copy pasted part from MS code:

namespace System.IdentityModel.Tokens.Jwt
{
    //
    // Summary:
    //     List of registered claims from different sources http://tools.ietf.org/html/rfc7519#section-4
    //     http://openid.net/specs/openid-connect-core-1_0.html#IDToken
    public struct JwtRegisteredClaimNames
    {
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Actort = "actort";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Typ = "typ";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Sub = "sub";
        //
        // Summary:
        //     http://openid.net/specs/openid-connect-frontchannel-1_0.html#OPLogout
        public const string Sid = "sid";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Prn = "prn";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Nbf = "nbf";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string Nonce = "nonce";
        //
        // Summary:
        //     http://tools.ietf.org/html/rfc7519#section-4
        public const string NameId = "nameid";
        
    }
}

Solution 9 - C#

You can't, because enum can only be based on a primitive numeric type. You could try using a Dictionary instead:

Dictionary<String, char> separators = new Dictionary<string, char>
{
    {"Comma", ','}, 
    {"Tab",  '\t'}, 
    {"Space", ' '},
};

Alternatively, you could use a Dictionary<Separator, char> or Dictionary<Separator, string> where Separator is a normal enum:

enum Separator
{
    Comma,
    Tab,
    Space
}

which would be a bit more pleasant than handling the strings directly.

Solution 10 - C#

For people arriving here looking for an answer to a more generic question, you can extend the static class concept if you want your code to look like an enum.

The following approach works when you haven't finalised the enum names you want and the enum values are the string representation of the enam name; use nameof() to make your refactoring simpler.

public static class Colours
{
	public static string Red => nameof(Red);
	public static string Green => nameof(Green);
	public static string Blue => nameof(Blue);
}

This achieves the intention of an enum that has string values (such as the following pseudocode):

public enum Colours
{
	"Red",
	"Green",
	"Blue"
}

Solution 11 - C#

Building on some of the answers here I have implemented a reusable base class that mimics the behaviour of an enum but with string as the underlying type. It supports various operations including:

  1. getting a list of possible values
  2. converting to string
  3. comparison with other instances via .Equals, ==, and !=
  4. conversion to/from JSON using a JSON.NET JsonConverter

This is the base class in it's entirety:

public abstract class StringEnumBase<T> : IEquatable<T>
    where T : StringEnumBase<T>
{
    public string Value { get; }

    protected StringEnumBase(string value) => this.Value = value;

    public override string ToString() => this.Value;

    public static List<T> AsList()
    {
        return typeof(T)
            .GetProperties(BindingFlags.Public | BindingFlags.Static)
            .Where(p => p.PropertyType == typeof(T))
            .Select(p => (T)p.GetValue(null))
            .ToList();
    }

    public static T Parse(string value)
    {
        List<T> all = AsList();

        if (!all.Any(a => a.Value == value))
            throw new InvalidOperationException($"\"{value}\" is not a valid value for the type {typeof(T).Name}");

        return all.Single(a => a.Value == value);
    }

    public bool Equals(T other)
    {
        if (other == null) return false;
        return this.Value == other?.Value;
    }

    public override bool Equals(object obj)
    {
        if (obj == null) return false;
        if (obj is T other) return this.Equals(other);
        return false;
    }

    public override int GetHashCode() => this.Value.GetHashCode();

    public static bool operator ==(StringEnumBase<T> a, StringEnumBase<T> b) => a?.Equals(b) ?? false;

    public static bool operator !=(StringEnumBase<T> a, StringEnumBase<T> b) => !(a?.Equals(b) ?? false);

    public class JsonConverter<T> : Newtonsoft.Json.JsonConverter
        where T : StringEnumBase<T>
    {
        public override bool CanRead => true;

        public override bool CanWrite => true;

        public override bool CanConvert(Type objectType) => ImplementsGeneric(objectType, typeof(StringEnumBase<>));

        private static bool ImplementsGeneric(Type type, Type generic)
        {
            while (type != null)
            {
                if (type.IsGenericType && type.GetGenericTypeDefinition() == generic)
                    return true;

                type = type.BaseType;
            }

            return false;
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JToken item = JToken.Load(reader);
            string value = item.Value<string>();
            return StringEnumBase<T>.Parse(value);
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value is StringEnumBase<T> v)
                JToken.FromObject(v.Value).WriteTo(writer);
        }
    }
}

And this is how you would implement your "string enum":

[JsonConverter(typeof(JsonConverter<Colour>))]
public class Colour : StringEnumBase<Colour>
{
    private Colour(string value) : base(value) { }

    public static Colour Red => new Colour("red");
    public static Colour Green => new Colour("green");
    public static Colour Blue => new Colour("blue");
}

Which could be used like this:

public class Foo
{
    public Colour colour { get; }

    public Foo(Colour colour) => this.colour = colour;

    public bool Bar()
    {
        if (this.colour == Colour.Red || this.colour == Colour.Blue)
            return true;
        else
            return false;
    }
}

I hope someone finds this useful!

Solution 12 - C#

I created a base class for creating string-valued enums in .NET. It is just one C# file that you can copy & paste into your projects, or install via NuGet package named StringEnum.

Usage:

///<completionlist cref="HexColor"/> 
class HexColor : StringEnum<HexColor>
{
    public static readonly HexColor Blue = New("#FF0000");
    public static readonly HexColor Green = New("#00FF00");
    public static readonly HexColor Red = New("#000FF");
}

Features

  • Your StringEnum looks somewhat similar to a regular enum:
    // Static Parse Method
    HexColor.Parse("#FF0000") // => HexColor.Red
    HexColor.Parse("#ff0000", caseSensitive: false) // => HexColor.Red
    HexColor.Parse("invalid") // => throws InvalidOperationException

    // Static TryParse method.
    HexColor.TryParse("#FF0000") // => HexColor.Red
    HexColor.TryParse("#ff0000", caseSensitive: false) // => HexColor.Red
    HexColor.TryParse("invalid") // => null

    // Parse and TryParse returns the preexistent instances
    object.ReferenceEquals(HexColor.Parse("#FF0000"), HexColor.Red) // => true

    // Conversion from your `StringEnum` to `string`
    string myString1 = HexColor.Red.ToString(); // => "#FF0000"
    string myString2 = HexColor.Red; // => "#FF0000" (implicit cast)
  • Intellisense will suggest the enum name if the class is annotated with the xml comment <completitionlist>. (Works in both C# and VB): i.e.

Intellisense demo

Instalation

Either:

  • Install latest StringEnum NuGet package, which is based on .Net Standard 1.0 so it runs on .Net Core >= 1.0, .Net Framework >= 4.5, Mono >= 4.6, etc.
  • Or paste the following StringEnum base class to your project. (latest version)
    public abstract class StringEnum<T> : IEquatable<T> where T : StringEnum<T>, new()
    {
        protected string Value;
        private static IList<T> valueList = new List<T>();
        protected static T New(string value)
        {
            if (value == null)
                return null; // the null-valued instance is null.

            var result = new T() { Value = value };
            valueList.Add(result);
            return result;
        }

        public static implicit operator string(StringEnum<T> enumValue) => enumValue.Value;
        public override string ToString() => Value;

        public static bool operator !=(StringEnum<T> o1, StringEnum<T> o2) => o1?.Value != o2?.Value;
        public static bool operator ==(StringEnum<T> o1, StringEnum<T> o2) => o1?.Value == o2?.Value;

        public override bool Equals(object other) => this.Value.Equals((other as T)?.Value ?? (other as string));
        bool IEquatable<T>.Equals(T other) => this.Value.Equals(other.Value);
        public override int GetHashCode() => Value.GetHashCode();

        /// <summary>
        /// Parse the <paramref name="value"/> specified and returns a valid <typeparamref name="T"/> or else throws InvalidOperationException.
        /// </summary>
        /// <param name="value">The string value representad by an instance of <typeparamref name="T"/>. Matches by string value, not by the member name.</param>
        /// <param name="caseSensitive">If true, the strings must match case sensitivity.</param>
        public static T Parse(string value, bool caseSensitive = false)
        {
            var result = TryParse(value, caseSensitive);
            if (result == null)
                throw new InvalidOperationException((value == null ? "null" : $"'{value}'") + $" is not a valid {typeof(T).Name}");

            return result;
        }

        /// <summary>
        /// Parse the <paramref name="value"/> specified and returns a valid <typeparamref name="T"/> or else returns null.
        /// </summary>
        /// <param name="value">The string value representad by an instance of <typeparamref name="T"/>. Matches by string value, not by the member name.</param>
        /// <param name="caseSensitive">If true, the strings must match case sensitivity.</param>
        public static T TryParse(string value, bool caseSensitive = false)
        {
            if (value == null) return null;
            if (valueList.Count == 0) System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); // force static fields initialization
            var field = valueList.FirstOrDefault(f => f.Value.Equals(value,
                    caseSensitive ? StringComparison.Ordinal
                                  : StringComparison.OrdinalIgnoreCase));
            // Not using InvariantCulture because it's only supported in NETStandard >= 2.0

            if (field == null)
                return null;

            return field;
        }
    }
  • For Newtonsoft.Json serialization support, copy this extended version instead. StringEnum.cs

I realized after the fact that this code is similar to Ben's answer. I sincerely wrote it from scratch. However I think it has a few extras, like the <completitionlist> hack, the resulting class looks more like an Enum, no use of reflection on Parse(), the NuGet package and repo where I will hopefully address incoming issues and feedback.

Solution 13 - C#

Well first you try to assign strings not chars, even if they are just one character. use ',' instead of ",". Next thing is, enums only take integral types without char you could use the unicode value, but i would strongly advice you not to do so. If you are certain that these values stay the same, in differnt cultures and languages, i would use a static class with const strings.

Solution 14 - C#

While it is really not possible to use a char or a string as the base for an enum, i think this is not what you really like to do.

Like you mentioned you'd like to have an enum of possibilities and show a string representation of this within a combo box. If the user selects one of these string representations you'd like to get out the corresponding enum. And this is possible:

First we have to link some string to an enum value. This can be done by using the DescriptionAttribute like it is described here or here.

Now you need to create a list of enum values and corresponding descriptions. This can be done by using the following method:

/// <summary>
/// Creates an List with all keys and values of a given Enum class
/// </summary>
/// <typeparam name="T">Must be derived from class Enum!</typeparam>
/// <returns>A list of KeyValuePair&lt;Enum, string&gt; with all available
/// names and values of the given Enum.</returns>
public static IList<KeyValuePair<T, string>> ToList<T>() where T : struct
{
	var type = typeof(T);

	if (!type.IsEnum)
	{
		throw new ArgumentException("T must be an enum");
	}

	return (IList<KeyValuePair<T, string>>)
			Enum.GetValues(type)
				.OfType<T>()
				.Select(e =>
				{
					var asEnum = (Enum)Convert.ChangeType(e, typeof(Enum));
					return new KeyValuePair<T, string>(e, asEnum.Description());
				})
				.ToArray();
}

Now you'll have a list of key value pairs of all enums and their description. So let's simply assign this as a data source for a combo box.

var comboBox = new ComboBox();
comboBox.ValueMember = "Key"
comboBox.DisplayMember = "Value";
comboBox.DataSource = EnumUtilities.ToList<Separator>();

comboBox.SelectedIndexChanged += (sender, e) =>
{
    var selectedEnum = (Separator)comboBox.SelectedValue;
    MessageBox.Show(selectedEnum.ToString());
}

The user sees all the string representations of the enum and within your code you'll get the desired enum value.

Solution 15 - C#

I wish there were a more elegant solution, like just allowing string type enum in the language level, but it seems that it is not supported yet. The code below is basically the same idea as other answers, but I think it is shorter and it can be reused. All you have to do is adding a [Description("")] above each enum entry and add a class that has 10 lines.

The class:

public static class Extensions
{
    public static string ToStringValue(this Enum en)
    {
        var type = en.GetType();
        var memInfo = type.GetMember(en.ToString());
        var attributes = memInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
        var stringValue = ((DescriptionAttribute)attributes[0]).Description;
        return stringValue;
    }
}

Usage:

    enum Country
    {
        [Description("Deutschland")]
        Germany,
        [Description("Nippon")]
        Japan,
        [Description("Italia")]
        Italy,
    }

    static void Main(string[] args)
    {
        Show(new[] {Country.Germany, Country.Japan, Country.Italy});

        void Show(Country[] countries)
        {
            foreach (var country in countries)
            {
                Debug.WriteLine(country.ToStringValue());
            }
        }
    }

Solution 16 - C#

Adding still something more as some of the answers here are missing the point of using enums. Naturally one option is is to have well defined strings as static variables etc, but then you're opening your interface for illegal values also, i.e. you need to validate the input. With enums it's guaranteed that only allowed values are passed to your interface.

enum Separator
{
    Comma,
    Tab,
    Space,
    CRLF,
    SoFunny
}

In addition to this you can use e.g. an internal Dictionary for the mapping purposes.

    private readonly Dictionary<Separator, string> separatorMap = new Dictionary<Separator, string>()
    {
        { Separator.Comma, "," },
        { Separator.Tab, "\t" },
        { Separator.Space, " " },
        { Separator.CRLF, "\r\n" },
        { Separator.SoFunny, "Your Mom" }
    };

Even more sophisticated method for doing this is to create a static class to give the enum new capabilities and handle the mapping there.

Example of using code above would be like.

public string TransformToSingleString(List<string> values, Separator separator)
{
    var separateWith = separatorMap[separator];
    ...
}

Solution 17 - C#

What I have recently begun doing is using Tuples

public static (string Fox, string Rabbit, string Horse) Animals = ("Fox", "Rabbit", "Horse");
...
public static (string Comma, string Tab, string Space) SeparatorChars = (",", "\t", " ");

Solution 18 - C#

> Enumaration Class

 public sealed class GenericDateTimeFormatType
    {
       
        public static readonly GenericDateTimeFormatType Format1 = new GenericDateTimeFormatType("dd-MM-YYYY");
        public static readonly GenericDateTimeFormatType Format2 = new GenericDateTimeFormatType("dd-MMM-YYYY");

        private GenericDateTimeFormatType(string Format)
        {
            _Value = Format;
        }

        public string _Value { get; private set; }
    }

> Enumaration Consuption

public static void Main()
{
       Country A = new Country();

       A.DefaultDateFormat = GenericDateTimeFormatType.Format1;

      Console.ReadLine();
}

Solution 19 - C#

We can't define enumeration as string type. The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong.

If you need more details on enumeration please follow below link,that link will help you to understand enumeration. Enumeration

@narendras1414

Solution 20 - C#

It works for me..

   public class ShapeTypes
    {
        private ShapeTypes() { }
        public static string OVAL
        {
            get
            {
                return "ov";
            }
            private set { }
        }

        public static string SQUARE
        {
            get
            {
                return "sq";
            }
            private set { }
        }

        public static string RECTANGLE
        {
            get
            {
                return "rec";
            }
            private set { }
        }
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSaeid YazdaniView Question on Stackoverflow
Solution 1 - C#Jon SkeetView Answer on Stackoverflow
Solution 2 - C#Amit Rai SharmaView Answer on Stackoverflow
Solution 3 - C#MaheepView Answer on Stackoverflow
Solution 4 - C#ThierryView Answer on Stackoverflow
Solution 5 - C#FischermaenView Answer on Stackoverflow
Solution 6 - C#Javier ContrerasView Answer on Stackoverflow
Solution 7 - C#komodospView Answer on Stackoverflow
Solution 8 - C#suchossView Answer on Stackoverflow
Solution 9 - C#AdamView Answer on Stackoverflow
Solution 10 - C#ZodmanView Answer on Stackoverflow
Solution 11 - C#BenView Answer on Stackoverflow
Solution 12 - C#Gerardo GrignoliView Answer on Stackoverflow
Solution 13 - C#dowhileforView Answer on Stackoverflow
Solution 14 - C#OliverView Answer on Stackoverflow
Solution 15 - C#Damn VegetablesView Answer on Stackoverflow
Solution 16 - C#Iso JView Answer on Stackoverflow
Solution 17 - C#Luke T O'BrienView Answer on Stackoverflow
Solution 18 - C#Rahul UttarkarView Answer on Stackoverflow
Solution 19 - C#Narendra1414View Answer on Stackoverflow
Solution 20 - C#Rakesh KrView Answer on Stackoverflow