Enum.Parse() vs switch performance - c#

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.

Related

How can I parse a string that represents a chain of generic methods?

In my app I need to parse a string like this, ".Add(20).Subtract(10).Add(2)" in a generic way into a series of method calls. In code I will supply the user with a value of T, and then expect the user to type an expression of the above format to calculate a new T from the expression. In the above example, I show the user an int and they typed the above string.
I need to aggregate any number of these chained string-representation of method calls into one cache-able property (delegate? Func<T,T>?) so that whenever a new value of T comes along it can be passed through the cached expression.
I initially thought there would be a way to aggregate these like a functional-programming pipeline, the outcome being a Func<T,T> that could represent the pipeline of methods. I'm guaranteed to know typeof(T) beforehand.
I'm hitting issues. Here's where I'm at:
I can regex the string with
\.(?<expName>[A-Z,a-z]+)\((?<expValue>[^)]+)\)
To get these matches:
expName
expValue
"Add"
"20"
"Subtract"
"10"
"Add"
"2"
I was expecting to use a TypeConverter to parse all expValue matches but I realized that given an arbitrary method T Foo(object arg) the arg can be any type to be determined by the specific method. The only guarantee is that a T input should always result in a T output.
We already know what type T is so we can theoretically map typeof(T) to a set of strings representing method names. I tried creating Dictionaries like this:
public static readonly Dictionary<string, Func<double, double, double>> DoubleMethods = new Dictionary<string, Func<double, double, double>>()
{
{"Add",(d,v)=>d+v },
{"Subtract",(d,v)=>d-v },
{"Multiply",(d,v)=>d*v },
{"Divide",(d,v)=>d/v }
};
public static Dictionary<string, Func<T, T, T>> TypeMethods<T>(Type t)
{
if(t.GetType() == typeof(double)) { return DoubleMethods; }
}
This won't compile, as I can't mix generics like this.
How do I create a linking structure that maps strings of predefined method names to a method, and then pass it the arg?
I also see that I will incur a bunch of boxing/unboxing penalties for arguments that happen to be primitive types, as in the example int.Add(int addedVal) method.
I believe I'm delving into parser/lexer territory without much familiarity.
Can you give an example of some code to point me in the right direction?
I'm not sure I see the need for the generics part:
var ops = "Add(20).Subtract(10).Divide(2).Multiply(5)";//25
var res = ops
.Split("().".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
.Chunk(2)
.Aggregate(0.0,(r,arr)=> r = DoubleMethods[arr[0]](r, double.Parse(arr[1])));
All those inputs parse as double, so let's just break the input string into chunks of 2 after splitting on the punctuation:
Add 20
Subtract 10
Divide 2
Multiply 5
Then run an agg op where we start from 0 (I wanted to start from 20 actually so that is what the add 20 is for)
The agg op looks up the method to call in the dictionary using the first element of the chunk
DoubleMethods[arr[0]]
And calls it passing in the current accumulator value r and the double parsing of the second element of the chunk:
(r, double.Parse(arr[1]))
and store the result into the accumulator for passing into the next op
I commented "do it in decimal" because it doesn't have floating point imprecision, but I used double just because your code did; you could swap to using decimal if you like, main point being that I can't see why you're worried about generics when decimal/double can store values one would encounter in ints too.
//basevalue is the value of the code your applying the change to.
soo... lets pretend the class is called number
Number ect = new Number(startingAmount)
in number we would have startingAmount = this.baseValue
public static T add(T baseValue, T change){
return baseValue+change;
}
public static T subtract(T baseValue, T change){
return baseValue-change;
}
public static T multiply(T baseValue, T change){
return baseValue*change;
}
public static T divide(T baseValue, T change){
return baseValue/change;
}
This should work... At least I hope it does
Here is a video on generics https://www.youtube.com/watch?v=K1iu1kXkVoA&t=1s
Java == c# so everything should be almost exactly the same

Why typeof(int).ToString() is not constant?

I'm trying to do this:
const string intType = typeof(int).ToString();
switch (typeof(MyT).ToString())
{
case intType:
{
return "int";
break;
}
...
}
But compiler says:
error CS0133: The expression being assigned to 'intType' must be constant
As I know, typeof operator works at compile-time. So, what's wrong?
As I know, typeof operator works at compile-time.
You don't know that because knowledge has to be true. Where did you get the idea that typeof is executed at compile time? It produces a non-constant object. And then there is no guarantee that ToString doesn't produce a different string every time it runs, so it cannot be treated as a constant either.
So, what's wrong?
You're reasoning from a false belief.
The C# specification clearly describes the conditions that must be met for an expression to be a compile-time constant. Those conditions include the expression not containing any typeof operator or method call.
But there are far bigger problems here. I assume that MyT is a generic type parameter, which means you are attempting to switch on the value of a generic type parameter. That is almost always the wrong thing to do.
What are you really trying to do? What problem are you really trying to solve? Because this code you've shown so far indicates that you're going down an unproductive path to solve whatever the real problem is.
I think, it is quite obvious, what he wants to achieve:
He wants to check for type equality in a switch-case instead of via if-elseif. And to be honest, why not? But how can he achieve this?
First option: Wait for C# 7.0. Yeah, shit like this is possible in the future!
Second option: Use strings. But the case strings need to be constant. So what about the wonderful nameof?
I just tried this "beauty" and it works, so maybe this solves your problem:
switch (typeof(Int32).Name)
{
case nameof(Int32):
Console.WriteLine("It's an Int32!");
break;
case nameof(Double):
Console.WriteLine("It's a Double");
break;
}
The only way to compare type MyT with known types is by checking their Type objects for equality. This can be done as follows:
if (typeof(MyT) == typeof(int)) return "int";
if (typeof(MyT) == typeof(decimal)) return "decimal";
// etc...
You cannot use this approach in a switch because (at the moment) a switch requires that the item being checked is of a simple type:
switch (typeof(T)) // Compile error: "switch expression or case label must be a bool,
// char, string, integral, enum, or corresponding nullable type"
{
case typeof(int): return "int";
case typeof(decimal): return "decimal";
// ...
}
Also, as others already said, checking types in this way almost always means that your approach can be improved by applying different object oriented principles.
E.g. instead of MyMethod<MyT>(MyT item) with type checks for MyT, consider making MyMethod(int item), MyMethod(decimal item) etc.
If you are just trying to get a string describing the type of object, you just need to call .GetType() instead.
For example, the following is a small function that will return the string name of the object type.
static string GetTypeString(object obj)
{
return obj.GetType().FullName;
}
This will return to the full path to the object. In int's case, it will return System.Int32. If you only want the Int32 part, use GetType().Name instead.
Also, you don't need to have a break; in a switch if you have a return;
If you have specific code that needs to be run for some types, or a specific string you want to return, you can use a string on the values returned by the above. For example:
static string GetSimpleType(object obj)
{
var stringRepresentation = GetTypeString(obj);
switch (stringRepresentation)
{
case "System.Int64":
case "System.Int32":
return "int";
default:
return stringRepresentation;
}
}
default is a catch all in switch statements for everything that does not have a case. Think of it like an else.
In the above example, we return the same value for int, Int32, and Int64. Case labels can fall through to other case labels if they are empty.
You can find all the values you need to write a switch for by running a simple script, and hard code the string values since they will always be the same for the same types. If the string is different, then the type is different.
Finally, if you are comparing types, if and if else works better:
static string GetSimpleType(object obj)
{
if (obj.GetType() == typeof(int))
{
return "int";
}
return obj.GetType().ToString();
}

Switch without cases (but with default) in System.Linq.Expressions

I have tried to create a switch expression with System.Linq.Expressions:
var value = Expression.Parameter(typeof(int));
var defaultBody = Expression.Constant(0);
var cases1 = new[] { Expression.SwitchCase(Expression.Constant(1), Expression.Constant(1)), };
var cases2 = new SwitchCase[0];
var switch1 = Expression.Switch(value, defaultBody, cases1);
var switch2 = Expression.Switch(value, defaultBody, cases2);
but in the last line I get an ArgumentException:
Non-empty collection required. Parameter name: cases
What is the reason of this exception? May be this a bug in Expression.Switch(…)?
In a C# a switch with "default" part only is correct:
switch(expr) {
default:
return 0;
}//switch
UPD: I have submitted an issue to the CoreFX repo on GitHub
There isn't a complete analogy between C#'s switch and SwitchExpression. In the other direction, consider that you can have:
var value = Expression.Parameter(typeof(int));
var meth = Expression.Lambda<Func<int, string>>(
Expression.Switch(
value,
Expression.Call(value, typeof(object).GetMethod("ToString")),
Expression.SwitchCase(Expression.Constant("Zero"), Expression.Constant(0, typeof(int))),
Expression.SwitchCase(Expression.Constant("One"), Expression.Constant(1, typeof(int)))),
value
).Compile();
Console.WriteLine(meth(0)); // Zero
Console.WriteLine(meth(1)); // One
Console.WriteLine(meth(2)); // 2
Here the SwitchExpression returns a value which is something switch cannot do.
So, just as being able to do something with SwitchExpression does not mean you can do it with a switch, so too there's no reason to assume that being able to do something with a switch means you can do it with a SwitchExpression.
That said, I see no good reason why SwitchExpression was set this way, except perhaps that it simplifies the case where an expression has no cases and no default body. That said, I think this was likely just a matter of the expression being generally intended to have multiple cases, and that was what it was coded to support.
I've submitted a pull-request to .NET Core that would allow such case-less expressions, by producing a SwitchExpression where the default value for the type of switchValue has the same body as the default body. This approach means anything that would be surprised by a SwitchExpression with no cases should still cope, avoiding backwards-compatibility issues. The case of there being no default either is dealt with by creating a noop expression that does nothing, so the only case that now still throws an ArgumentException is if there is no case and no default and the type is explicitly set to something other than void, this case being invalid under the typing rules that must obviously still be kept.
[Update: That approach was rejected, but a later pull-request was accepted, so case-less SwitchExpressions are now allowed by .NET Core, though if and when that is adopted by other versions of .NET is another matter].
In the meantime, or if you use another version of .NET, you're best-off using a helper method like:
public static Expression SwitchOrDefault(Type type, Expression switchValue, Expression defaultBody, MethodInfo comparison, IEnumerable<SwitchCase> cases)
{
if (cases != null)
{
// It's possible that cases is a type that can only be enumerated once.
// so we check for the most obvious condition where that isn't true
// and otherwise create a ReadOnlyCollection. ReadOnlyCollection is
// chosen because it's the most efficient within Switch itself.
if (!(cases is ICollection<SwitchCase>))
cases = new ReadOnlyCollection<SwitchCase>(cases);
if (cases.Any())
return Switch(type, switchValue, defaultBody, comparison, cases);
}
return Expression.Block(
switchValue, // include in case of side-effects.
defaultBody != null ? defaultBody : Expression.Empty() // replace null with a noop expression.
);
}
Overloads like:
public static Expression SwitchOrDefault(Expression switchValue, Expression defaultBody, params SwitchCase[] cases)
{
return SwitchOrDefault(switchValue, defaultBody, null, (IEnumerable<SwitchCase>)cases);
}
And so on can then be added.
This results in a trimmer Expression overall than my pull-request, because it cuts out the switch entirely in the no-cases case and just returns the default body. If you really need to have a SwitchExpression then you could create a similar helper method that follows the same logic as that pull-request does in creating a new SwitchCase and then using that.

Enum.Parse() or Switch

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;
}

Converting code using generics

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 :)

Categories

Resources