Reputation: 14132
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 = " "}
Upvotes: 178
Views: 722899
Reputation: 1133
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 (In the deserialized response payload). This also can be seen in Andrew Whitaker answer.
[UPDATE]
Based on the comments below, some people may want to use the EnumMemberValue in C#. For that we can use the following extension:
public static string? ToEnumMember<T>(this T value) where T : Enum
{
return typeof(T)
.GetTypeInfo()
.DeclaredMembers
.SingleOrDefault(x => x.Name == value.ToString())?
.GetCustomAttribute<EnumMemberAttribute>(false)?
.Value;
}
Now we can use it in C#.
var unitString = myEnum.Kilometers.ToEnumMember();
Happy coding.. :)
Upvotes: 71
Reputation: 494
Way after the party but for anyone stumbling across this SO posting, you could always fashion something customized like this, where you could match your "simulated" enum
types like you do with regular enums
and also access the "underlying" string
value via MyEnumObject.Value
:
public class MyEnumType
{
public readonly string Value;
public static readonly MyEnumType MyStringEnum1 = new MyEnumType("String 1");
public static readonly MyEnumType MyStringEnum2 = new MyEnumType("String 2");
public static readonly MyEnumType MyStringEnum3 = new MyEnumType("String 3");
public static readonly MyEnumType MyStringEnum4 = new MyEnumType("String 4");
private MyEnumType(string value)
{ this.Value = value; }
}
Usage:
public string? MyStringEnumMethod(MyEnumType enumObj)
{
switch (enumObj)
{
case MyEnumType.MyStringEnum1:
//Do something
return enumObj.Value;
case MyEnumType.MyStringEnum3:
//Do something else
return enumObj.Value;
default:
return null;
}
}
Upvotes: 1
Reputation: 4225
You can achieve it but it will require a bit of work.
Define an attribute class which will contain the string value for enum.
Define an extension method which will return back the value from the attribute. e.g.GetStringValue(this Enum value)
will return attribute value.
Then you can define the enum like this..
public enum Test : int {
[StringValue("a")]
Foo = 1,
[StringValue("b")]
Something = 2
}
To get back the value from Attribute Test.Foo.GetStringValue();
Refer : Enum With String Values In C#
Upvotes: 149
Reputation: 199
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];
...
}
Upvotes: 2
Reputation: 12514
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());
}
}
}
Upvotes: 6
Reputation: 15217
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.
///<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");
}
// 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)
<completitionlist>
. (Works in both C# and VB): i.e.Either:
.Net Standard 1.0
so it runs on .Net Core
>= 1.0, .Net Framework
>= 4.5, Mono
>= 4.6, etc. 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;
}
}
Newtonsoft.Json
serialization support, copy this extended version instead. StringEnum.csI 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.
Upvotes: 7
Reputation: 2845
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", " ");
Upvotes: 7
Reputation: 49
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 { }
}
}
Upvotes: -1
Reputation: 3934
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"
}
Upvotes: 11
Reputation: 5715
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:
.Equals
, ==
, and !=
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!
Upvotes: 4
Reputation: 3065
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";
}
}
Upvotes: 15
Reputation: 3658
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"
}
Upvotes: 28
Reputation: 909
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;
Upvotes: 90
Reputation: 27
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
Upvotes: -1
Reputation: 3645
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();
}
Upvotes: 0
Reputation: 5605
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 " ";} }
}
Upvotes: 105
Reputation: 45109
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<Enum, string> 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.
Upvotes: 2
Reputation: 15813
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.
Upvotes: 13
Reputation: 11051
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.
Upvotes: 2
Reputation: 1504182
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();
}
Upvotes: 153
Reputation: 12468
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 = " ";
}
Upvotes: 36