For converting a string to an enum, which of the following ways is better?
This code:
colorEnum color = (colorEnum)Enum.Parse(typeof(colorEnum), "Green");
or this:
string colorString = ...
colorEnum color;
switch (colorString)
{
case "Green":
color = colorEnum.Green;
break;
case "Red":
color = colorEnum.Red;
break;
case "Orange":
color = colorEnum.Orange;
break;
....
}
You should use the Enum.TryParse, if it fails you can handle the error correctly.
sample:
ColorsEnum colorValue;
if (Enum.TryParse(colorString, out colorValue))
if (Enum.IsDefined(typeof(Colors), colorValue) | colorValue.ToString().Contains(","))
Console.WriteLine("Converted '{0}' to {1}.", colorString, colorValue.ToString());
else
Console.WriteLine("{0} is not an underlying value of the Colors enumeration.", colorString);
else
Console.WriteLine("{0} is not a member of the Colors enumeration.", colorString);
(Warning: includes plug for my own open source library...)
Personally I'd use Unconstrained Melody, which ends up with cleaner and more typesafe code:
ColorEnum color = Enums.ParseName<ColorEnum>(text);
You can use TryParseName if you suspect it may be invalid. Obviously this requires an extra library, but hopefully you'll find other things in there helpful too :)
Enum.TryParse from .NET 4 is better than the other built-in options, but:
You won't catch non-enum types at compile time, e.g. Enum.TryParse<int>(...) will still compile; Unconstrained Melody really only allows enum types
Enum.TryParse will also parse "1" (or whatever the numeric value is when converted to a string) - if you really only expect names, I think it's better to only accept names
I definitely wouldn't switch on the string values - it means if you rename the enum values, you've got to remember to rename the case value as well.
And what about Enum.TryParse<TEnum> ?
string myColorStr = "red";
colorEnum myColor;
if(!Enum.TryParse<colorEnum>(myColorStr, true, out myColor))
{
throw new InvalidOperationException("Unknown color " + myColorStr);
}
Number 1 simply on readability and maintainability. If you extend the enum you need to do no extra work, wheras with 2 you have to add more cases to the switch statement
Because you added the tag 'performance', I'm going to go with the switch.
Yes, you will have to change the cases when you rename/add/remove anything in the enum. Well that's just too bad then. Any variant of Enum.Parse/TryParse uses a lot of weird code and some reflection, just take a look inside the function with ILSpy or such. Then there is also the issue of accepting "-12354" and even a comma-separated list of valid names (resulting in all of them ORed together) even when the enum doesn't have a [Flags] attribute.
As an alternative, you could make a dictionary that translates enum names to values. It should actually be faster than the switch, because a switch on strings also goes through a dictionary but you save the actual switch part.
Obviously both ways cost some more maintenance than enum.parse and variants; whether it's worth it is up to you, since out of all of us only you have enough knowledge of the project to make the performance/coding-time trade off.
1) Is much better. It's cleaner code. You are doing in one line what would take multiple in 2). Also, it's less bug prone. When you add another item to colorEnum, you would need to remember to extend 2) wheras 1) would just work.
You may also want some error handling on the Enum.Parse.
Other than the fact that the two different code snippets doesn't do the same thing, I'd use this:
colorEnum color;
if (!colorEnum.TryParse(colorString, true, out color)
color = colorEnum.Green; // Or whatever default value you wish to have.
If you don't have .NET 4.0 then I'd do something like this:
public static TEnum ToEnum<TEnum>(this string strEnumValue, TEnum defaultValue)
{
if (!Enum.IsDefined(typeof(TEnum), strEnumValue))
return defaultValue;
return (TEnum)Enum.Parse(typeof(TEnum), strEnumValue);
}
This is an Extension Method to string.
Personally, while I am totally fine with the Enum.Parse solution for non-performance scenarios (read: one off run of this function occasionally ... and there are many such scenarios to be sure), I can't countenance the thought of possibly involving some reflection type method when this function needs to be performed in a loop over hundreds/thousands plus enum values at once. Gack!
So the following is a solution that gets some of the best of both worlds.
Just retrieve all values of the enum at startup time or what not, whenever it works best for you (below is one way of doing that), and then construct a Dictionary with them.
private static Dictionary<string, Color> colorDictionary;
public static Dictionary<string, Color> ColorDictionary
{
get
{
if (colorDictionary== null) {
colorDictionary = new Dictionary<string, Color>();
var all = Enum.GetValues(typeof(Color)).OfType<Color>();
foreach (var val in all)
dict.Add(val.ToString(), val);
}
return colorDictionary;
}
}
I find the switch variant horrible since you will have to modify the switch everytime you change the enum also.
I like to use the TryParse that belongs to your enum. So you can use it like this
string colorString = .....
colorEnum color;
colorEnum.TryParse(colorString, out color);
Or if you don't care about the case of the string
colorEnum.TryParse(colorString, true, out color);
The returnvalue of TryParse is true if the string was a valid enum, false if not.
On a performance point of view, as enums are implemented as static fields, the parse method will probably ends up doing refection on then enum type and try a GetField method which might be faster than the case. On the other end, if 90% of the case, the color is green, the case will be very fast... Note that the CLR sometimes rearrange code internally, changing the order of the case based on statistic (actually, I'm not sure it does that but the doc claims it could).
I use the following, it gets you all the type safety while still not falling over when you add new values into the Enum, it's also very fast.
public static colorEnum? GetColorFromString(string colorString)
{
colorEnum? retVal = null;
if(Enum.IsDefined(typeof(colorEnum), colorString))
retVal = (colorEnum)Enum.Parse(typeof(colorEnum), colorString);
return retVal;
}
My test with 8 items in the enum shows this way to be faster than the switch method.
Or else you can use (the very slow way):
public static colorEnum? GetColorFromString(string colorString)
{
foreach (colorEnum col in Enum.GetValues(typeof(colorEnum)))
{
if (col.ToString().Equals(colorString))
{
return col;
}
}
return null;
}
Related
I'm doing a little C# program, but it is configurable. Properties.Settings.Default.foobar is equal to F3, but that is subject to change. Originally it'd be this way:
case Keys.F3:
//dostuff
break;
But I need Properties.Settings.Default.foobar in place of F3, since it's a setting and thus subject to change.
case Keys.Properties.Settings.Default.foobar:
Obviously doesn't work, nor does putting it in parenthesis, so I'm not sure. I'm clearly new to C#, so any help?
The program uses unfocused hotkeys, but these keys are user configurable, so I can't have any sort of constant/static for a case, right?
case Keys.Properties.Settings.Default.foobar:
As you say, this obviously doesn't work. The specific reason is that the values for a case statement must be compile-time constants.
A simpler if comparison would probably be better. Since your value is a Keys and your property is a string, you'll need to convert one type to the other for comparison. I'll convert to a string for simplicity, or you could convert the string to the enum type.
if (myVar.ToString() == Properties.Settings.Default.foobar)
So instead of having, e.g.
switch (myVar) {
case Keys.F1:
// something
case Keys.F2:
// something
}
You would have:
if (myVar.ToString() == Properties.Settings.Default.foo) {
// something
} else if (myVar.ToString() == Properties.Settings.Default.bar) {
// something
}
Keys.F3 is a value of the Keys enumeration. So you'll need to convert your Properties.Settings.Default.foobar string into a value of the enumeration too.
Luckily, there is a built-in method to do that:
var foobarKey = (Keys)Enum.Parse(typeof(Keys), Properties.Settings.Default.foobar);
...
if (whatever == foobarKey)
{
...
Everything is in the title, I've read this question Enum.Parse() or Switch but there is nothing about performance. My Enum is around 10 members long, I'd like to know which one is faster, switch or Enum.Parse() ?
Nice and fast:
public static class EnumHelpers<TTarget>
{
static EnumHelpers()
{
Dict = Enum.GetNames(typeof(TTarget)).ToDictionary(x => x, x => (TTarget)Enum.Parse(typeof(TTarget), x), StringComparer.OrdinalIgnoreCase);
}
private static readonly Dictionary<string, TTarget> Dict;
public static TTarget Convert(string value)
{
return Dict[value];
}
}
switch is always faster, since parse uses reflection to get the names of the members.. but unless the application is performance critical.. (thousands of executions per second).. using Enum.Parse makes code easier to maintain
I've built a fast "switch" version using expression trees.
public static Func<String, TEnum> GetParseEnumDelegate<TEnum>()
{
var eValue = Expression.Parameter(typeof(String), "value"); // (String value)
var tEnum = typeof(TEnum);
return
Expression.Lambda<Func<String, TEnum>>(
Expression.Block(tEnum,
Expression.Switch(tEnum, eValue,
Expression.Block(tEnum,
Expression.Throw(Expression.New(typeof(Exception).GetConstructor(Type.EmptyTypes))),
Expression.Default(tEnum)
),
null,
Enum.GetValues(tEnum).Cast<Object>().Select(v => Expression.SwitchCase(
Expression.Constant(v),
Expression.Constant(v.ToString())
)).ToArray()
)
), eValue
).Compile();
}
...
var parseEnum = GetParseEnumDelegate<YourEnum>();
YourEnum e = parseEnum("SomeEnumValue");
If you need a non-generic version, you must convert the result of the switch from tEnum to typeof(Object).
public static Func<String, Object> GetParseEnumDelegate(Type tEnum)
{
var eValue = Expression.Parameter(typeof(String), "value"); // (String value)
var tReturn = typeof(Object);
return
Expression.Lambda<Func<String, Object>>(
Expression.Block(tReturn,
Expression.Convert( // We need to box the result (tEnum -> Object)
Expression.Switch(tEnum, eValue,
Expression.Block(tEnum,
Expression.Throw(Expression.New(typeof(Exception).GetConstructor(Type.EmptyTypes))),
Expression.Default(tEnum)
),
null,
Enum.GetValues(tEnum).Cast<Object>().Select(v => Expression.SwitchCase(
Expression.Constant(v),
Expression.Constant(v.ToString())
)).ToArray()
), tReturn
)
), eValue
).Compile();
}
I did several perf tests and this delegate version was almost as fast as the native switch. In my scenario (enum with 10 items) it was 5 times faster than Enum.Parse().
As #CaldasGSM answered, the biggest problem is the reflection that is happening inside the Enum.Parse method. In addition just the number of IF's used in the Enum.Parse internal implementation is much higher than the number of conditions in your switch statement, not to count the other code inside that method. All of that makes it much inferior to a switch.
If you are processing a small number of items like you said than there is actually no significant difference if you are using Enum.Parse vs switch. For a large number of items it is a different story.
However, i would add that one more problem with Enum.Parse is that you have to handle three exception types using try-catch blocks in cases your parsing doesn't work, which will slow down your code as well.
In addition you should also not overlook the cost of boxing the enum values in the object type when using Enum.Parse, which is also a performance penalty.
To resolve the mentioned issues a much better alternative is to use the newer Enum.TryParse API, which will make it simpler to handle errors, and also prevent the boxing to object, since it uses generics.
Here is an example:
Items item;
if (!Enum.TryParse("First", true, out item))
{
// Handle error
}
In isolation, the switch will be faster.
But code rarely executes in isolation. Typically, the user will have entered a value, or you will have loaded it from a disk file. The whole purpose of Enum is to have a symbolic representation of a string value so that you can work with it more easily. It also allows you to validate the data that's entered.
So, let's say you have an enumeration:
public enum Thing
{
Foo,
Bar,
Fooby,
Barby
}
And somebody gives you a string that's supposed to represent one of those. You write a switch statement:
switch (s)
{
case "Foo": break;
case "Bar": break;
case "Fooby": break;
case "Barby": break;
default : throw new ArgumentException();
}
What happens if the user entered "foo"? Are you going to reject it because the case isn't correct? Very unfriendly behavior. So you modify your code to do a ToLower() on the string, and modify your cases to use all lower case.
It's crazy. Your code will be much easier to understand and maintain if you use Enum.TryParse to convert it to an enum, and then do what needs to be done using the enum value.
Use a switch (I prefer using parse anyway because of it's more maintainable).
Anyway, premature optimization is the root of all evil.
I've following code that uses the passed Object and acts on it after determining its type. My question is that if I convert it to use generics, will I get any performance advantage since I'd still have to determine the type of T before I act upon it? Will I save ticks on boxing/unboxing?
private void BindOptionFields(Object obj, String selectedValue, int dataLanguageID)
{
String typ = obj.GetType().Name;
switch(typ.ToLower())
{
case "ratingscaleitem":
SetRatingScale((Common.RatingScaleItem)obj, dataLanguageID, selectedValue);
break;
case "taskstatus":
text = ((TaskStatus)obj).TaskName;
optionValue = ((TaskStatus)obj).StateID.ToString();
break;
case "planlite":
text = ((XYZ.ABC.PlanLite)obj).PlanName;
optionValue = ((XYZ.ABC.PlanLite)obj).Id.ToString();
break;
case "datarow":
text = ((DataRow)obj)["TextColumn"].ToString();
optionValue = ((DataRow)obj)["KeyColumn"].ToString();
break;
default:
break;
}
if (optionValue == selectedValue)
{
selected = true;
}
}
Note: I've 3 constructors in my class that receive an ArrayList of 20 different types (similar types in ArrayList for a particular call). I loop through the arraylist and call this BindOptionFields() so if I've to write overloaded methods, I'll have to overload my constructors for 20 cases each. Can someone suggest a less tedious solution that would be fast as well?
You're misunderstanding generics.
If you convert this method to a generic method, the caller will need to specify the generic parameter at compile-time.
At that point, you can just use a normal set of overloaded methods.
Would it not be better to add a BindOptionField method (perhaps as part of an Interface e.g. IOptionFieldBindable) to the types you're switching on here?
The TaskStatus, PlanLite, and DataRow Types are good candidates particularly, since they're each providing a different way to set the same two values. That way, you could just call
(obj as IOptionFieldBindable).BindOptionField(text, optionValue);
Your solution would also be less Stringly Typed :)
I have defined a C# enum as
public enum ORDER
{
...
unknown,
partial01,
partial12,
partial23,
}
and can use its value as a string as in:
string ss = ORDER.partial01.ToString();
However when I try to use it in a case statement it fails to compile:
string value = ...
switch (value)
{
case null:
break;
case "s":
// OK
break;
case ORDER.partial01.ToString():
// compiler throws "a constant value is expected"
break;
...
I thought enums were constants. How do I get around this?
(I cannot parse the value into an enum as some of the values are outside the range)
Since C# 6, you can use: case nameof(SomeEnum.SomeValue):
Nameof is evaluated at compile time, simply to a string that matches the (unqualified) name of the given variable, type, or member. Naturally, it changes right along should you ever rename the enum option name.
Convert the string in your switch to an enum value.
(ORDER)Enum.Parse(typeof(ORDER), value, true);
The enum is a constant, but the result of .ToString() is not. As far as the compiler is concerned, it is a dynamic value. You probably need to convert your switch case into a series of if/else statements
As an alternative to using if .. else, you could convert your string to an enum first. It would probably not make much sense if the number of options is small though:
if (Enum.IsDefined(typeof(ORDER), value))
{
switch ((ORDER)Enum.Parse(typeof(ORDER), value)
{
case ORDER.partial01:
// ...
break;
case ORDER.partial12:
// etc
}
}
else
{
// Handle values not in enum here if needed
}
*sigh* if only there was a built-in T Enum.Parse<T>(string value), and a TryParse version :)
You designed this as an enum for a reason, but you're not really making use of it as an enum. Why are you taking the enum value and converting it to a string to then use in the switch instead of simply using the enum?
You said that you can't parse this in to an enum because some of the values are outside the enum range. The question to ask then is, "Why?" What is the point of having the enum if you are allowing values that aren't defined? What is it that you want to happen when you get a value that isn't defined? If it's the same thing for any undefined value, then you can use the default case. If it's not, then you can include additional cases that match the numeric representation.
If you really do get strings back, then you probably don't want to use an enum. Instead you want to create a public static class containing public string constants, which you can then use in your switch. The trick here is that the evaluation will be done in a case sensitive manner.
public static class Order
{
public const string Unknown = "Unknown";
public const string Partial01 = "Partial01";
public const string Partial12 = "Partial12";
public const string Partial23 = "Partial23";
}
string value = Order.Partial01
switch (value)
{
case Order.Partial01:
break;
default:
// Code you might want to run in case you are
// given a value that doesn't match.
break;
}
(You might also want to clean up your casing.)
As Thorarin indicated, if your switch statement can contain only enum cases, convert your string to an enum first. At least as of .Net framework 4, you can use the Enum.TryParse()<TEnum> method as defined here and do something like:
ORDER orderEnum = ORDER.unknown;
Enum.TryParse<ORDER>(value, out orderEnum);
switch (orderEnum)
{
case ORDER.unknown:
// perhaps do something to deal with cases not matching
// to known enum values, based on the string value
break;
case ORDER.partial01:
case ORDER.partial12:
case ORDER.partial23:
// map value to known cases, etc.
break;
}
Enum values are constants, but you're trying to use the results of a method (ORDER.partial01.ToString()), not a constant.
The best option, in my opinion, would be to just switch this around to using if/else if/else statements, instead of a switch. This would allow you to use the logic you are desiring.
Alternatively, if you switch your string into the enum value, you can switch on the enum values directly. You cannot switch on the enum + null + other strings, though, in one switch.
Couldn't you just instead say
case "partial01":
?
enums are constant but ToString() is a function returning a value. based on the instance of the enum object it's being called on.
That is the two statements:
ORDER.partial01.ToString()
ORDER.partial02.ToString()
calls the same function but returns two different values, so the call to the function .ToString() is in it self not a constant value.
This is not a static value as far as the compiler is concerned, since it is a function call:
ORDER.partial01.ToString()
Therefore, you can't use it as a comparison in a case statement. However, you can simply do this:
case "partial01"
That would work, since the enum value and the string are identical.
Use Extension
public static string ToGender(this Gender enumValue)
{
switch (enumValue)
{
case Gender.Female:
return "Female";
case Gender.Male:
return "Male";
default:
return null;
}
}
Example
Gender.Male.ToGender();
simply you can define a global variable
static ORDER orderstr;
now you can set the value of orderstr anywhere in the page
public enum ORDER
{
unknown,
partial01,
partial12,
partial23,
}
switch (orderstr)
{
case Order.Partial01:
break;
default:
break;
}
I have a switch statement in one class that generates Command objects, based on if a certain line in a code file matches the particular code for that Command object.
like this:
switch (line):
{
case "#CODE1":
return new Command1();
case "#CODE2":
return new Command2();
}
I want to turn it into something like this:
switch (line):
{
case Command1.Code:
return new Command1();
case Command2.Code:
return new Command2();
}
I tried it by creating a public static property of Command1, but the compiler complains...
Is there a way to do something along this intent, that the compiler won't complain about?
I think you can do this only with constants... so if it's possible for you, use constant fields instead of public static properties. The difference is that it's treated like a literal at compile time, so if the value changes, you would need to recompile all assemblies that reference the constant.
Switch only works on numeric types and string types, not properties. You can try defining a public string constant on your Command1 and Command2 class, which you should be able to switch on instead.
public class Command1
{
public string const Code = "#CODE1";
}
since you are working with strings I'm not sure if it's the best approach, but using enums works for me
enum CommandEnum { CommandOne, ComandTwo, CommandN }
//...
CommandEnum myCommand;
//...
switch (myCommand)
{
case myCommand.CommandOne:
return new Command1();
case myCommand.CommandTwo:
return new Command2();
//...
}
You could always fall back on the tried and true if / else block
if (line == Command1.Code)
return new Command1();
else if (line == Command2.Code)
return new Command2();
That's not so evil, is it?
I think your problem is you need to instantiate your objects before you can determine their property values.
I'm assuming you have a code file with tokenized instructions, like:
#CODE1
#CODE2
and you want a class to read each line of your file and then perform whichever instructions the tokens define.
You got it to work, but instead of doing a direct string comparison to the token in the file, you want the value of the token stored in a property of your objects? The problem with that approach is you have to create a new instance of your object (commands 1 and 2) before you can refer to their property values.
If I understand what you've done and what you want to do, I think your solution was fine the way it was. I'm not 100% sure I really understand what you want to do, though, or why.
HTH
If you want to check against properties on a class. I'm assuming that you probably want to be able to change those properties and check accordingly. You'll have to use an if, else if, else if type statement.
If you've got a jones to use a switch statement, you're SOL unless you're checking an integral type against constant values. if, else if, else if blocks are ugly, but it'll do what you're looking for.