I'm interested in both style and performance considerations. My choice is to do either of the following ( sorry for the poor formatting but the interface for this site is not WYSIWYG ):
One:
string value = "ALPHA";
switch ( value.ToUpper() )
{
case "ALPHA":
// do somthing
break;
case "BETA":
// do something else
break;
default:
break;
}
Two:
public enum GreekLetters
{
UNKNOWN= 0,
ALPHA= 1,
BETA = 2,
etc...
}
string value = "Alpha";
GreekLetters letter = (GreekLetters)Enum.Parse( typeof( GreekLetters ), value.ToUpper() );
switch( letter )
{
case GreekLetters.ALPHA:
// do something
break;
case GreekLetters.BETA:
// do something else
break;
default:
break;
}
Personally, I prefer option TWO below, but I don't have any real reason other than basic style reasons. However, I'm not even sure there really is a style reason. Thanks for your input.
The second option is marginally faster, as the first option may require a full string comparison. The difference will be too small to measure in most circumstances, though.
The real advantage of the second option is that you've made it explicit that the valid values for value fall into a narrow range. In fact, it will throw an exception at Enum.Parse if the string value isn't in the expected range, which is often exactly what you want.
Option #1 is faster because if you look at the code for Enum.Parse, you'll see that it goes through each item one by one, looking for a match. In addition, there is less code to maintain and keep consistent.
One word of caution is that you shouldn't use ToUpper, but rather ToUpperInvariant() because of Turkey Test issues.
If you insist on Option #2, at least use the overload that allows you to specify to ignore case. This will be faster than converting to uppercase yourself. In addition, be advised that the Framework Design Guidelines encourage that all enum values be PascalCase instead of SCREAMING_CAPS.
I can't comment on the performance part of the question but as for style I prefer option #2. Whenever I have a known set of values and the set is reasonably small (less than a couple of dozen or so) I prefer to use an enum. I find an enum is a lot easier to work with than a collection of string values and anyone looking at the code can quickly see what the set of allowed values is.
This actually depends on the number of items in the enum, and you would have to test it for each specific scenario - not that it is likely to make a big difference. But it is a great question.
With very few values, the Enum.Parse is going to take more time than anything else in either example, so the second should be slower.
With enough values, the switch statement will be implemented as a hashtable, which should work the same speed with strings and enums, so again, Enum.Parse will probably make the second solution slower, but not by relatively as much.
Somewhere in the middle, I would expect the cost of comparing strings being higher than comparing enums would make the first solution faster.
I wouldn't even be surprised if it were different on different compiler versions or different options.
I would definitely say #1. Enum.Parse() causes reflection which is relatively expensive. Plus, Enum.Parse() will throw an Exception if its not defined and since there's no TryParse() you'd need to wrap it in Try/Catch block
Not sure if there is a performance difference when switching on a string value versus an enum.
One thing to consider is would you need the values used for the case statements elsewhere in your code. If so, then using an enum would make more sense as you have a singular definition of the values. Const strings could also be used.
Related
What is the benefit/downside to using a switch statement vs. an if/else in C#. I can't imagine there being that big of a difference, other than maybe the look of your code.
Is there any reason why the resulting IL or associated runtime performance would be radically different?
Related: What is quicker, switch on string or elseif on type?
SWITCH statement only produces same assembly as IFs in debug or compatibility mode. In release, it will be compiled into jump table (through MSIL 'switch' statement)- which is O(1).
C# (unlike many other languages) also allows to switch on string constants - and this works a bit differently. It's obviously not practical to build jump tables for strings of arbitrary lengths, so most often such switch will be compiled into stack of IFs.
But if number of conditions is big enough to cover overheads, C# compiler will create a HashTable object, populate it with string constants and make a lookup on that table followed by jump. Hashtable lookup is not strictly O(1) and has noticeable constant costs, but if number of case labels is large, it will be significantly faster than comparing to each string constant in IFs.
To sum it up, if number of conditions is more than 5 or so, prefer SWITCH over IF, otherwise use whatever looks better.
In general (considering all languages and all compilers) a switch statement CAN SOMETIMES be more efficient than an if / else statement, because it is easy for a compiler to generate jump tables from switch statements. It is possible to do the same thing for if / else statements, given appropriate constraints, but that is much more difficult.
In the case of C#, this is also true, but for other reasons.
With a large number of strings, there is a significant performance advantage to using a switch statement, because the compiler will use a hash table to implement the jump.
With a small number of strings, the performance between the two is the same.
This is because in that case the C# compiler does not generate a jump table. Instead it generates MSIL that is equivalent to IF / ELSE blocks.
There is a "switch statement" MSIL instruction that when jitted will use a jump table to implement a switch statement. It only works with integer types, however (this question asks about strings).
For small numbers of strings, it's more efficient for the compiler to generate IF / ELSE blocks then it is to use a hash table.
When I originally noticed this, I made the assumption that because IF / ELSE blocks were used with a small number of strings, that the compiler did the same transformation for large numbers of strings.
This was WRONG. 'IMA' was kind enough to point this out to me (well...he wasn't kind about it, but he was right, and I was wrong, which is the important part)
I also made a bone headed assumption about the lack of a "switch" instruction in MSIL (I figured, if there was a switch primitive, why weren't they using it with a hash table, so there must not be a switch primitive.... ). This was both wrong, and incredibly stupid on my part. Again 'IMA' pointed this out to me.
I made the updates here because it's the highest rated post, and the accepted answer.
However,I've made it Community Wiki because I figure I don't deserve the REP for being wrong. If you get a chance, please up vote 'ima''s post.
The compiler is going to optimize pretty much everything into the same code with minor differences (Knuth, anyone?).
The difference is that a switch statement is cleaner than fifteen if else statements strung together.
Friends don't let friends stack if-else statements.
Three reasons to prefer the switch:
A compiler targeting native code can often compile a switch statement into one conditional branch plus an indirect jump whereas a sequence of ifs requires a sequence of conditional branches. Depending on the density of cases a great many learned papers have been written about how to compile case statements efficiently; some are linked from the lcc compiler page. (Lcc had one of the more innovative compilers for switches.)
A switch statement is a choice among mutually exclusive alternatives and the switch syntax makes this control flow more transparent to the programmer then a nest of if-then-else statements.
In some languages, including definitely ML and Haskell, the compiler checks to see if you have left out any cases. I view this feature as one of the major advantages of ML and Haskell. I don't know if C# can do this.
An anecdote: at a lecture he gave on receiving an award for lifetime achievement, I heard Tony Hoare say that of all the things he did in his career, there were three that he was most proud of:
Inventing Quicksort
Inventing the switch statement (which Tony called the case statement)
Starting and ending his career in industry
I can't imagine living without switch.
Actually, a switch statement is more efficient. The compiler will optimize it to a lookup table whereas with if/else statements it cannot. The downside is that a switch statement can't be used with variable values.
You can't do:
switch(variable)
{
case someVariable:
break;
default:
break;
}
it has to be:
switch(variable)
{
case CONSTANT_VALUE:
break;
default:
break;
}
I didn't see anyone else raise the (obvious?) point that the supposed efficiency advantage of the switch statement is dependent on the various cases being approximately equally likely. In cases where one (or a few) of the values are much more likely, the if-then-else ladder can be much faster, by ensuring the most common cases are checked first:
So, for example:
if (x==0) then {
// do one thing
} else if (x==1) {
// do the other thing
} else if (x==2) {
// do the third thing
}
vs
switch(x) {
case 0:
// do one thing
break;
case 1:
// do the other thing
break;
case 2:
// do the third thing
break;
}
If x is zero 90% of the time, the "if-else" code can be twice as fast as the switch-based code. Even if the compiler turns the "switch" into some kind of clever table-driven goto, it still won't be as fast as simply checking for zero.
often it will look better - ie will be easier to understand what's going on. Considering the performance benefit will be extremely minimal at best, the view of the code is the most important difference.
So, if the if/else looks better, use it, otherwise use a switch statement.
Side topic, but I often worry about (and more often see) if/else and switch statement get way too large with too many cases. These often hurt maintainability.
Common culprits include:
Doing too much inside of multiple if statements
More case statements than humanly possible to analyze
Too many conditions in the if evaluation to know what is being looked for
To fix:
Extract to Method refactoring.
Use a Dictionary with method pointers instead of a case, or use an IoC for added configurability. Method factories also can be helpful.
Extract the conditions to their own method
If you are just using if or else statement the base solution is using the comparsion ? operator
(value == value1) ? (type1)do this : (type1)or do this;
You can do the or routine in a switch
switch(typeCode)
{
case TypeCode:Int32:
case TypeCode.Int64:
//dosomething here
break;
default: return;
}
As per this link, IF vs Switch comparison of iteration test using switch and if statement, is like for 1,000,000,000 iterations, Time taken by Switch Statement=43.0s & by If Statement = 48.0s
Which is literally 20833333 iterations per second, So, Should we really need to focus more,
P.S:Just to know the performance difference for small list of conditions.
This doesn't actually answer your question, but given there will be little difference between the compiled versions, I would urge you to write your code in a way that best describes your intentions. Not only is there a better chance of the compiler doing what you expect, but it will make it easier for others to maintain your code.
If your intention is to branch your program based on the value of one variable/attribute, then a switch statement best represents that intention.
If your intention is to branch your program based on different variables/attributes/conditions, then a if/else if chain best represents that intention.
I will grant that cody is right about people forgetting the break command, but almost as frequently I see people doing complicated if blocks where they get the { } wrong, so lines that should be in the conditional statement are not. It's one of the reasons I always include { } on my if statements even if there's one line in it. Not only is it easier to read, but if I need to add another line in the conditional, I can't forget to add it.
Interest question. This came up a few weeks ago at work and we found an answer by writing an example snippet and viewing it in .NET Reflector (reflector is awesome!! i love it).
This is what we discovered:
A valid switch statement for anything other than a string gets compiled to IL as a switch statement. However IF it is a string it is rewritten as a if/else if/else in IL. So in our case we wanted to know how switch statements compare strings e.g is case-sensitive etc. and reflector quickly gave us an answer. This was useful to know.
If you want to do case-sensitive compare on strings then you could use a switch statement as it is faster than performing a String.Compare in an if/else. (Edit: Read What is quicker, switch on string or elseif on type? for some actual performance tests) However if you wanted to do a case-insensitive then it is better using a if/else as the resulting code is not pretty.
switch (myString.ToLower())
{
// not a good solution
}
The best rule of thumb is to use switch statements if it makes sense (seriously), e.g:
it improves the readability of your code
you are comparing a range of values (float, int) or an enum
If you need to manipulate the value to feed into the switch statement (create a temporary variable to switch against) then you probably should be using an if/else control statement.
An update:
It is actually better to convert the string to uppercase (e.g. ToUpper()) as that has been apparently there are further optimizations that the just-in-time compiler can do as when compared to the ToLower(). It is a micro optimization, however in a tight loop it could be useful.
A little side note:
To improve the readability of switch statements try the following:
put the most likely branch first i.e. most accessed
if they are all likely to occur, list them in alphabetical order so it is easier to find them.
never use the default catch-all for the last remaining condition, that's lazy and will cause issues later on in the code's life.
use the default catch-all to assert an unknown condition even though it highly unlikely it will ever occur. that is what asserts are good for.
Not just C#, but all C-based languages, I think: because a switch is limited to constants, it's possible to generate very efficient code using a "jump table". The C case is really a good old FORTRAN computed GOTO, but the C# case is still tests against a constant.
It is not the case that the optimizer will be able to make the same code. Consider, eg,
if(a == 3){ //...
} else if (a == 5 || a == 7){ //...
} else {//...
}
Because those are compound booleans, the generated code has to compute a value, and shortcircuit. Now consider the equivalent
switch(a){
case 3: // ...
break;
case 5:
case 7: //...
break;
default: //...
}
This can be compiled into
BTABL: *
B3: addr of 3 code
B5:
B7: addr of 5,7 code
load 0,1 ino reg X based on value
jump indirect through BTABL+x
because you are implicitly telling the compiler that it doesn't need to compute the OR and equality tests.
The switch statement is definitely the faster then a if else if. There are speedtest that have been supplied on it by BlackWasp
http://www.blackwasp.co.uk/SpeedTestIfElseSwitch.aspx
--Check it out
But depends heavily on the possibilities that you're trying to account for, but I try to use a switch statement whenever possible.
My 2 cents on it. Well most of the times if performance is not a criteria than it's more about code readability. If the the number of if/else statements are too many than using switch statement is better.
My cs professor suggested not to you switch statements since so often people forgot the break or use it incorrectly. I can;t recall exactly what he said but something along the lines that looking at some seminal code base that showed examples of the switch statement (years ago) had a tons of mistakes in it also.
Something that I just noticed is that you can combine if/else and switch statements! Very useful when needing to check preconditions.
if (string.IsNullOrEmpty(line))
{
//skip empty lines
}
else switch (line.Substring(0,1))
{
case "1":
Console.WriteLine(line);
break;
case "9":
Console.WriteLine(line);
break;
default:
break;
}
I Think Switch Is More Faster Than If Conditions
like see if There is a program like :
Write a Program to enter any number (between 1 – 99) and check it is in which slot a) 1 – 9 then slot one b) 11 – 19 then slot two c) 21-29 then slot three and so on till 89-99
Then On If You Have Have To Make Many Conditions But Son Switch Case You Have TO Just Type
Switch ( no /10 )
and on case 0 = 1-9 ,case 1 = 11-19 and so on
it will Be So Easy
There Are Many More Such Examples Also!
a switch statement basicly is a comparison for equality. keyboard event's have a great advantage over switch statement's when having easy to write and read code then an if elseif statement would, missing a {bracket} could get troubling as well.
char abc;
switch(abc)
{
case a: break;
case b: break;
case c: break;
case d: break;
}
An if elseif statement is great for more then one solution if(theAmountOfApples is greater then 5 && theAmountOfApples is less then 10) save your apples
else if(theAmountOfApples is greater then 10 || theAmountOfApples == 100) sell your apples. I dont write c# or c++ but I did learn it before I learned java and they are close languages.
One possible downside of switch statements is its lack of multiple conditions. You can have multiple conditions for the if (else) but not multiple cases statements with different conditions in a switch.
Switch statements are not suitable for logic operations beyond the scope of simple Boolean equations/expressions. For those Boolean equations/expressions, it is eminently suitable but not for other logic operations.
You have much more freedom with the logic available in If statements but the readability can suffer if the If statement becomes unwieldy or is handled poorly.
Both have there place depending on the context of what you are faced with.
After reading all the answers before me and browsing all over the web I can say switch case statements can help you to make your code look more neat and manageable. And the performance is also better than else if statements when I tested in my project, because I have to check more than 10 cases (it might sound weird!).
I would like to know if there is a better more efficient way to use if statements rather than just long lines of
if(){
//code
}else if(){
//code
} else{
//code
}
I've done some research on the site and I found this:
If you have only 2 values, I strongly suggest to use the code you posted, because is likely the most readable, elegant and fast code possible (IMHO).
But if you have more cases like that and more complicated, you could
think to use a switch statement:
switch (el.type)
{
case ElementType.Type1:
case ElementType.Type2:
case ElementType.Type3:
//code here
break;
case ElementType.Type4:
case ElementType.Type5:
//code here
break;
case ElementType.Type6:
//code here
break;
}
that translated in if statements would be:
if (el.type == ElementType.Type1 ||
el.type == ElementType.Type2 ||
el.type == ElementType.Type3 )
{
// code here
}else if(el.type == ElementType.Type4 ||
el.type == ElementType.Type5)
{
// code here
}else if(el.type == ElementType.Type6)
{
// code here
}
They're perfectly equal to me, but the switch seems more readable/clearer, and you need to type less (i.e. it's "shorter" in term of code length) :)
Although I don't quite understand what it is telling me, is it saying that a switch statement is a better use for long if statements or?
To have some context surrounding my problem, I have a Windows Forms application with some radio buttons - A questionnaire if you will - I want to know if there is more efficient ways that reduces repetitive unnecessary lines of code and replaces them with short code that does the same job.
The goal should be more readable / clearer code, which does not always mean the shortest statement.
If you have very complex logic, with lots of nested if / else branches, try to split it in smaller, simpler routines.
Switch statements as well as many if-else statements are often a sign of the smelly design.
Consider refactoring into a more object-oriented design
If-else not much more readable than switch-case and vice-versa.
You could apply CoR pattern.
Here you will fine one of .NET implementations.
When you combine this with IoC container you may achieve very flexible architecture...
switch statements are not only easier to read, they are easier for the compiler to optimize because they explicitly specify one value you are triggering all the code off of. The compiler can easily optimize this using a hash or a jump table rather than a sequence of comparisons, making it much faster (when it can do so). Technically, it could detect that the if statements are the same thing, but may or may not be sophisticated enough to do so. So, if you have 256 separate cases triggering off the value of a byte, a switch can be compiled into a hard coded array of code offsets (each entry in the array is the offset of the code handling that case), and no comparison is done at all because it can just use the byte value as an index into the hard coded array and jump to the correct code. This is much faster than doing 255 (or 256) compares.
Switches using string values are also handled specially, using hash codes for better performance. You may be able to do something similar explicitly, but your code will be much less readable.
Using a string.CompareTo(string) i can get around this slightly but is not easy to read and i have read on that locallity settings might influence the result.
Is there a way to just simply use < or > on 2 Strings in a more straightforward way?
You can overload operators but you seldom should. To me "stringA" > "stringB" wouldn't mean a damn thing, it's not helping readability IMO. That's why operator overloading guidelines advise not to overload operators if the meaning is not obvious.
EDIT: Operator Overloading Usage Guidelines
Also, in case of String I'm afraid you can't do it seeing as you can put operator-overloading methods only in the class in which the methods are defined.
If the syntax of CompareTo bothers you, maybe wrapping it in extension method will solve your problem?
Like that:
public static bool IsLessThan(this string str, string str2) {
return str.Compare(str2) < 0;
}
I still find it confusing for reader though.
The bottom line is, you can't overload operators for String. Usually you can do something like declaring a partial and stuffing your overloads there, but String is a sealed class, so not this time. I think that the extension method with reasonable name is your best bet. You can put CompareTo or some custom logic inside it.
CompareTo is the proper way in my opinion, you can use the overloads to specify culture specific parameters...
You mention in a comment that you're comparing two strings with values of the form "A100" and "B001". This works in your legacy VB 6 code with the < and > operators because of the way that VB 6 implements string comparison.
The algorithm is quite simple. It walks through the string, one character at a time, and compares the ASCII values of each character. As soon as a character from one string is found to have a lower ASCII code than the corresponding character in the other string, the comparison stops and the first string is declared to be "less than" the second. (VB 6 can be forced to perform a case-insensitive comparison based on the system's current locale by placing the Option Compare Text statement at the top of
the relevant code module, but this is not the default setting.)
Simple, of course, but not entirely logical. Comparing ASCII values skips over all sorts of interesting things you might find in strings nowadays; namely non-ASCII characters. Since you appear to be dealing with strings whose contents have pre-defined limits, this may not be a problem in your particular case. But more generally, writing code like strA < strB is going to look like complete nonsense to anyone else who has to maintain your code (it seems like you're already having this experience), and I encourage you to do the "right thing" even when you're dealing with a fixed set of possible inputs.
There is nothing "straightforward" about using < or > on string values. If you need to implement this functionality, you're going to have to do it yourself. Following the algorithm that I described VB 6 as using above, you could write your own comparison function and call that in your code, instead. Walk through each character in the string, determine if it is a character or a number, and convert it to the appropriate data type. From there, you can compare the two parsed values, and either move on to the next index in the string or return an "equality" value.
There is another problem with that, I think:
Assert.IsFalse(10 < 2);
Assert.IsTrue("10" < "2");
(The second Assert assumes you did an overload for the < operator on the string class.)
But the operator suggests otherwise!!
I agree with Dyppl: you shouldn't do it!
I have an algorithm that returns a list of classifications(strings) dependant on the two arguments given to the algorithm: a type variable, and an extra category string that allows certain special classifications to be added to the result list.
The current implementation, is unreadable and unscalable due to the expression of the rules as ifs, and switch statements. Also the rules are hard coded.
A simplified version of the code:
private static List<string> DetermineTypes(Type x, object category) {
List<string> Types = new List<string>();
if (category is DateTime) {
types.Add("1");
types.Add("2");
types.Add("3");
} else if (category is string) {
switch ((string)category) {
case "A":
Types.Add("4");
break;
case "B":
case "C":
case "D":
Types.Add("5");
break;
case "":
Types = DetermineTypesFromX(Types, x);
break;
default:
Types.Add("6");
break;
}
}
return graphTypes;
}
private static List<string> DetermineTypesFromX(List<string> Types, Type x) {
if (x.Equals(typeof(int))) {
Types.Add("7");
} else if (x.Equals(typeof(double))) {
Types.Add("8");
} else if (x.Equals(typeof(System.DateTime))) {
Types.Add("9");
Types.Add("10");
}
return Types;
}
I was thinking that it would be good to maybe specify these with xml, so that a code change wasn't needed for new types/rules, but that is most probably too heavyweight for the situation. Basically I am trying to solve the problem that a new 'Type' may be added at anytime: common case would be that it is one of the 'rules' above, and an unlikely edge case that a new 'rule' branch may have to be added.
I am still to determine whether the work needed it to make it fully dynamic using xml defined rules( or any other way) is worth it compared to the likelihood of the edge cases ever happening and the business environment(schedules etc).
But my main point of the question is how could you elegantly simplify the nested conditional code above? maybe incorporating more flexibility into the design for increased scalability?
I was wondering if using a combination of F# pattern matching might be an appropriate solution? (NB: Never used F# before, have been curious as of late, so thats why I am asking)
A pattern known as dispatch tables has been recently discussed in the following two blog posts and will probably be of interest to you:
Aaron Feng
K. Scott Allen
I wouldn't shy away from a config-based option; it usually has the advantage of not requiring a rebuild. If you don't want that, another option might be type-metadata via an attribute. This would make it trivial to add data for new types (that you write), and you can (indirectly) add attributes to exiting types (int etc) via TypeDescriptor.AddAttributes - as long as you use TypeDescriptor.GetAttributes to get them back out again ;-p
Whether this is a good idea or not... well, reflection (and the twin, TypeDescriptor) can be slow, so if you want to use this in a tight loop I'd look first at something involving a dictionary.
Your problem may be coded in terms of decision tree or decision table
Also, there is posts into Chris Smith's blog about decision trees:
Awesome F# - Decision Trees – Part I and
Awesome F# - Decision Trees – Part II
I would suggest you look at a business rules/inference engine. NxBRE has a good community around it and is quite mature. This may be beyond your immediate requirements but if you expect these rules to increase in complexity over time a BRE will provide a nice framework to keep things under control.
Since you mention F#, here is some F# code with very similar behavior to the C# code:
open System
let DetermineTypesFromX(x:Type) =
if x.Equals(typeof<int>) then
["7"]
elif x.Equals(typeof<double>) then
["8"]
elif x.Equals(typeof<DateTime>) then
["9"; "10"]
else
[]
let DetermineTypes(x:Type, category:obj) =
match category with
| :? DateTime -> ["1"; "2"; "3"]
| :? string as s ->
match s with
| "A" -> ["4"]
| "B" | "C" | "D" -> ["5"]
| "" -> DetermineTypesFromX(x)
| _ -> ["6"]
| _ -> []
That said, I would recommend considering a table-driven approach as an alternative to hard-coded if/switch logic, regardless of whether you move the logic out of the code and into a config file.
I came across similar situation and I've asked a few questions previously in regards to the similar problem that may help you.
The system I did was a configuration driven, rule based dynamic system. All configurations and rules were saved in database. Decision tables were constructed dynamically based on the values and rules retrived from database. Values were then converted and compared in C#. Here's the question I asked about dynamic decision table in C#. And the question regarding dyanmically convert and compare values retrived from databse.
So I end up having something simliar to this in terms of the config table (just an example):
Conditions IsDecision LHS Operator RHS
TTFF False PostCode > 100
TFTF False PostCode < 10000
FTTT True
Note: LHS is the property name of the object.
The above table in plain English:
Condition 1 PostCode > 100 Yes Yes No No
Condition 2 PostCode < 10000 Yes No Yes No
Outcome 1 Yes
Outcome 2 Yes
Outcome 3 Yes
Outcome 4 Yes
Then you have other tables/configs to determine the action for each outcome.
The core parts of the implementation are how to dynamically construct decision table and how to dynamic convert and compare string values, all of which I have provided links to the specific implementations in the above paragraph. I believe you can apply similar concepts in your situations and I hope I've explained the concept in general.
Other Resources:
Martin Fowler's decision tree article.
Luke's post on decision tree.
I am building a fun little app to determine if I should bike to work.
I would like to test to see if it is either Raining or Thunderstorm(ing).
public enum WeatherType : byte
{ Sunny = 0, Cloudy = 1, Thunderstorm = 2, Raining = 4, Snowing = 8, MostlyCloudy = 16 }
I was thinking I could do something like:
WeatherType _badWeatherTypes = WeatherType.Thunderstorm | WeatherType.Raining;
if(currentWeather.Type == _badWeatherTypes)
{
return false;//don't bike
}
but this doesn't work because _badWeatherTypes is a combination of both types. I would like to keep them separated out because this is supposed to be a learning experience and having it separate may be useful in other situations (IE, Invoice not paid reason's etc...).
I would also rather not do: (this would remove the ability to be configured for multiple people)
if(WeatherType.Thunderstorm)
{
return false; //don't bike
}
etc...
Your current code will say whether it's exactly "raining and thundery". To find out whether it's "raining and thundery and possibly something else" you need:
if ((currentWeather.Type & _badWeatherTypes) == _badWeatherTypes)
To find out whether it's "raining or thundery, and possibly something else" you need:
if ((currentWeather.Type & _badWeatherTypes) != 0)
EDIT (for completeness):
It would be good to use the FlagsAttribute, i.e. decorate the type with [Flags]. This is not necessary for the sake of this bitwise logic, but affects how ToString() behaves. The C# compiler ignores this attribute (at least at the moment; the C# 3.0 spec doesn't mention it) but it's generally a good idea for enums which are effectively flags, and it documents the intended use of the type. At the same time, the convention is that when you use flags, you pluralise the enum name - so you'd change it to WeatherTypes (because any actual value is effectively 0 or more weather types).
It would also be worth thinking about what "Sunny" really means. It's currently got a value of 0, which means it's the absence of everything else; you couldn't have it sunny and raining at the same time (which is physically possible, of course). Please don't write code to prohibit rainbows! ;) On the other hand, if in your real use case you genuinely want a value which means "the absence of all other values" then you're fine.
I'm not sure that it should be a flag - I think that you should have an range input for:
Temperature
How much it's raining
Wind strength
any other input you fancy (e.g. thunderstorm)
you can then use an algorithm to determine if the conditions are sufficiently good.
I think you should also have an input for how likely the weather is to remain the same for cycling home. The criteria may be different - you can shower and change more easliy when you get home.
If you really want to make it interesting, collect the input data from a weather service api, and evaulate the decision each day - Yes, I should have cycled, or no, it was a mistake. Then perhaps you can have the app learn to make better decisions.
Next step is to "socialize" your decision, and see whether other people hear you are making the same decisions.
use the FlagsAttribute. That will allow you to use the enum as a bit mask.
You need to use the [Flags] attribute (check here) on your enum; then you can use bitwise and to check for individual matches.
You should be using the Flags attribute on your enum. Beyond that, you also need to test to see if a particular flag is set by:
(currentWeather.Type & WeatherType.Thunderstorm == WeatherType.Thunderstorm)
This will test if currentWeather.Type has the WeatherType.Thunderstorm flag set.
I wouldn't limit yourself to the bit world. Enums and bitwise operators are, as you found out, not the same thing. If you want to solve this using bitwise operators, I'd stick to just them, i.e. don't bother with enums. However, I'd something like the following:
WeatherType[] badWeatherTypes = new WeatherType[]
{
WeatherType.Thunderstorm,
WeatherType.Raining
};
if (Array.IndexOf(badWeatherTypes, currentWeather.Type) >= 0)
{
return false;
}