Well i got this if else statement where i have 12 variables that can either be 0, 1, or 2. if its a 0 its pass, if its 1 it fails, if its a 2 its unknown. I was wondering if anyone knows a shorter way of writing it in C#
here is what i have to write if there isn't
string pass = "pass";
string fail = "fail";
string unknown = "unknown"
if ( value == 0)
{
test1 = pass;
}
else if (value == 1)
{
test1 = fail;
}
else if (value == 2)
{
test1 = unknown;
}
if ( value1 == 0)
{
test2 = pass;
}
else if (value1 == 1)
{
test2 = fail;
}
else if (value1 == 2)
{
test2 = unknown;
}
.
.
.
if ( value12 == 0)
{
test13 = pass;
}
Let me explain a little more. I have 12 pictures on webpage, that need to be updated, depending on a database for the values. Each picture can be only 1 of 3 options and can change depending on the database. A pass(check mark), a fail(a red x) and an unknown (question mark). Let me know if you need more details.
Well i got this if else statement where i have 12 variables that can either be 0 1 or 2.
Any time you have several variables which you want to be able to treat in a similar way, you should use a collection for them, e.g. an array or a List<T>. If you don't already have a collection for them, you can create one:
int[] values = { value0, value, value2 /* etc * };
... although it would be better if you could have them as a collection from the very start.
Then you can iterate over all of them. It's not really clear why in this case you're overwriting the value of test in each block, but having a collection of inputs ends up with a natural way of creating a collection of outputs. You can also use a switch statement or a conditional expression to make the checks simpler. For example:
public static string ConvertValueToLabel(int value)
{
switch (value)
{
case 0: return "pass";
case 1: return "fail";
case 2: return "unknown";
// Adjust this behaviour as appropriate...
default: throw new ArgumentOutOfRangeException("value");
}
}
Or:
public static string ConvertValueToLabel(int value)
{
// Note that this doesn't do the same range checking as the version above
return value == 0 ? "pass"
: value == 1 ? "fail"
: "unknown";
}
(Some people don't like "stacking" conditionals like this, and I probably wouldn't use it in this case where a switch statement is probably more sensible, but it can be really handy.)
Looks like a case for arrays.
int[] values = { 1, 1, 2, 2, 1, 2 };
for (int i = 0; i < values.Length; i++)
{
if (values[i] == 1)
{
}
else if (values[i] == 2)
{
}
}//for
According to your code there is no need to check values 0-11 cause the test variable is changed again using value12. So you can just check the last value and and skip all other.
I would write a for loop which checks each variable. Or, at the very least, write the check as a function which can be referenced with each variable. Do the former if the variables are in series and their names can be determined sequentially. Do the later if the variable names are not really related to each other.
If necessary, place the variables into an array which can be looped through.
Related
For a part of my project, I want to enforce the rule that the user input can only be within a min/max word boundary. With a minimum of 1 word, and a maximum of 50 words. The boolean isn't changing from the default set value of false. Here is my code:
bool WordCount_Bool = false;
//Goto the method that handles the calculation of whether the users input is within the boundary.
WordCount_EH(WordCount_Bool);
//Decide whether to continue with the program depending on the users input.
if (WordCount_Bool == true)
{
/*TEMP*/MessageBox.Show("Valid input");/*TEMP*/
/*Split(split_text);*/
}
else
{
MessageBox.Show("Please keep witin the Min-Max word count margin.", "Error - Outside Word Limit boundary");
}
Method handling the array and the change of the boolean:
private bool WordCount_EH(bool WordCount_Bool)
{
string[] TEMPWordCount_Array = input_box.Text.Split(' ');
int j = 0;
int wordcount = 0;
for (int i = 100; i <=0; i--)
{
if (string.IsNullOrEmpty(TEMPWordCount_Array[j]))
{
//do nothing
}
else
{
wordcount++;
}
j++;
}
if (wordcount >= 1)
{
WordCount_Bool = true;
}
if (wordcount < 1)
{
WordCount_Bool = false;
}
return WordCount_Bool;
}
Thank you all in advance.
Side note: I realize that the for loop will throw an exception or at least is not optimal for its purpose so any advice will be much appreciated.
Extra Side note: Sorry I should have said that the reason i haven't used length is that wherever possible I should do my own code instead of using built-in functions.
The short answer is you should just return a true or false value from your WordCount_EH method like others have said
But just to clear up why it doesn't work. C# by default passes arguments by value. With Value types such as Boolean the actual value of true or false is stored in the variable. So when you pass your Boolean value into your method all you are doing is saying please put this bool value into my new variable (the method parameter). When you make changes to that new variable it only changes that variable. It has no relation to the variable that it was copied from. This is why you don't see a change in original bool variable. You may have named the variables the same but they are infact two different variables.
Jon Skeet explains it fantastically here http://jonskeet.uk/csharp/parameters.html
Here you go this should solve it:
if(input_box.Text.Split(' ').Length>50)
return false;
else
return true;
You need to pass WordCount_Bool by ref if you want to change it in WordCount_EH:
private bool WordCount_EH(ref bool WordCount_Bool) { ... }
bool WordCount_Bool = false;
WordCount_EH(ref WordCount_Bool);
although in this case you might as well use the return value:
bool WordCount_Bool = false;
WordCount_Bool = WordCount_EH(WordCount_Bool);
If you want to pass argument by reference, you need to do as per #Lee suggestion.
For your logic implementation, you can use following code to avoid array indexing.
// It would return true if you word count is greater than 0 and less or equal to 50
private bool WordCount_EH()
{
var splittedWords = input_box.Text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
return (splittedWords.Count > 0 && splittedWords.Count <= 50);
}
I am currently working on a program and I am finalising it by going over with error handling. I have several cases which look like:
int stockbankInput = Convert.ToInt32(Console.ReadLine());
Here, the user must enter either 1, 2, 3. I have tried to use an if statement to catch the error if anybody inputs a blankspace/string/character or a number that is not 1,2 or 3 but it doesn't work in the same sense as a string input. Below is what I have tried:
if(stockbankInput == null)
{
Console.WriteLine("Error: Please enter either 1, 2 or 3");
stockbankInput = 0;
goto menuRestartLine;
}
However, you cannot link 'null' with an integer input, only a string. Can anybody help with this please?
Use the Int32 TryParse method:
int input;
var successful = Int32.TryParse(Console.ReadLine(), out input);
if (!successful)
// do something else
else
return input;
You're checking if an int is null, which will always return false because an int cannot be null.
You can use 'int?' (Nullable int) but Convert.ToInt32 will not return null. If the value of the int cannot be resolved it will resolve to the default value of zero. You can either check if the returned int is zero or do some further checking of the returned string:
int input = 0;
string errorMessage = "Error: Please enter either 1, 2 or 3";
while(true)
{
try
{
input = Convert.ToInt32(Console.ReadLine());
if (input == 0 || input > 3)
{
Console.WriteLine(errorMessage);
}
else
{
break;
}
}
catch(FormatException)
{
Console.WriteLine(errorMessage);
}
}
With this you your returned value "int input" will either be 0 or the number you entered and FormatExceptions caused by the string to convert containing symbols other than the digits 0-9 will be caught in the try/catch statement.
give this sample program a try:
static void Main(string[] args)
{
int stockbankInput = 0;
bool firstTry = true;
while(stockbankInput < 1 | stockbankInput > 3)
{
if(!firstTry)
Console.WriteLine("Error: Please enter either 1, 2 or 3");
firstTry = false;
Int32.TryParse(Console.ReadLine(), out stockbankInput);
}
}
First of all, don't use goto statements. They are considered bad practice, and it's like a blinding red light when reading your question - that's all I can focus on.
As per your question, an int or Int32 cannot be null. So you can't compare it to null. Give it a default value, and then check that.
This is a scenario where you don't need to check for an error, but just need to validate input. Use TryParse, which will set your out parameter if the parse is successful, or else set it to 0.
Next, you want to loop until you are given good input. An if statement is executed once, a loop will guarantee that when you leave it, your input will be valid.
Lastly, the firstTry is just a nice way to let the user know, after their first try, that they screwed up.
Okay, i have a list and where i have structs stored, and i need to go through them from the last to the first, to check if one of the variables in the struct is 1. the code look like this:
for(int i = (checkpoints.Count - 1); i == 0; i--)
{
if(checkpoints[i].active == 1)
{
playerPositionX = checkpoints[i].xPosition;
playerPositionY = checkpoints[i].yPosition;
camPositionX = checkpoints[i].xPosition;
break;
}
}
this is the struct that i use:
private struct checkpoint
{
public int xPosition;
public int yPosition;
public int active;
}
what i need to do is to check if the variable active is == 1 in the struct that i have stored in the list. i have around 3-8 structs stored in the list. I need to start the check from the last struct in the list and work my way to the first.
when i try to debug the program it looks like it's not going from the last, but it starts at i=0.
please leave a comment if you have a fix, or if you need more information.
You can also use LastOrDefault() function. But, here can be one problem, because we are searching for Struct.
If nothing found?
LastOrDefault() will return default(checkpoint) if nothing found. The default value of a struct is the struct with all its values in turn default initialized. So, we must cast them to nullable using .Cast<checkpoint?>.
var activeCheckPoint = checkpoints
.Where(x => x.active == 1)
.Cast<checkpoint?>()
.LastOrDefault();
Or we must do the second check afterward that the returned object's active value is 1.
var activeCheckPoint = checkpoints.LastOrDefault(x => x.active == 1);
if(actactiveCheckPoint.active == 1)
{
// Then it is Ok
}
else
{
// Nothins was found
}
But, if you want to use for loop, then you must change i == 0 to i >= 0.
Your mistake was that you said to go though the loop if i was equal to 0, when it wasn't. You want the loop to loop until i is greater or equal to zero.
for(int i = (checkpoints.Count - 1); i >= 0; i--) // your mistake was here
{
if(checkpoints[i].active == 1)
{
playerPositionX = checkpoints[i].xPosition;
playerPositionY = checkpoints[i].yPosition;
camPositionX = checkpoints[i].xPosition;
break;
}
}
Cyclomatic Complexity will be high for methods with a high number of decision statements including if/while/for statements. So how do we improve on it?
I am handling a big project where I am supposed to reduced the CC for methods that have CC > 10. And there are many methods with this problem. Below I will list down some eg of code patterns (not the actual code) with the problems I have encountered. Is it possible that they can be simplified?
Example of cases resulting in many decision statements:
Case 1)
if(objectA != null) //objectA is a pass in as a parameter
{
objectB = doThisMethod();
if(objectB != null)
{
objectC = doThatMethod();
if(objectC != null)
{
doXXX();
}
else{
doYYY();
}
}
else
{
doZZZ();
}
}
Case 2)
if(a < min)
min = a;
if(a < max)
max = a;
if(b > 0)
doXXX();
if(c > 0)
{
doYYY();
}
else
{
doZZZ();
if(c > d)
isTrue = false;
for(int i=0; i<d; i++)
s[i] = i*d;
if(isTrue)
{
if(e > 1)
{
doALotOfStuff();
}
}
}
Case 3)
// note that these String Constants are used elsewhere as diff combination,
// so you can't combine them as one
if(e.PropertyName.Equals(StringConstants.AAA) ||
e.PropertyName.Equals(StringConstants.BBB) ||
e.PropertyName.Equals(StringConstants.CCC) ||
e.PropertyName.Equals(StringConstants.DDD) ||
e.PropertyName.Equals(StringConstants.EEE) ||
e.PropertyName.Equals(StringConstants.FFF) ||
e.PropertyName.Equals(StringConstants.GGG) ||
e.PropertyName.Equals(StringConstants.HHH) ||
e.PropertyName.Equals(StringConstants.III) ||
e.PropertyName.Equals(StringConstants.JJJ) ||
e.PropertyName.Equals(StringConstants.KKK))
{
doStuff();
}
Case 1 - deal with this simply by refactoring into smaller functions. E.g. the following snippet could be a function:
objectC = doThatMethod();
if(objectC != null)
{
doXXX();
}
else{
doYYY();
}
Case 2 - exactly the same approach. Take the contents of the else clause out into a smaller helper function
Case 3 - make a list of the strings you want to check against, and make a small helper function that compares a string against many options (could be simplified further with linq)
var stringConstants = new string[] { StringConstants.AAA, StringConstants.BBB etc };
if(stringConstants.Any((s) => e.PropertyName.Equals(s))
{
...
}
You should use the refactoring Replace Conditional with Polymorphism to reduce CC.
The difference between conditional an polymorphic code is that the in polymorphic code the decision is made at run time. This gives you more flexibility to add\change\remove conditions without modifying the code. You can test the behaviors separately using unit tests which improves testability. Also since there will be less conditional code means that the code is easy to read and CC is less.
For more look into behavioral design patterns esp. Strategy.
I would do the first case like this to remove the conditionals and consequently the CC. Moreover the code is more Object Oriented, readable and testable as well.
void Main() {
var objectA = GetObjectA();
objectA.DoMyTask();
}
GetObjectA(){
return If_All_Is_Well ? new ObjectA() : new EmptyObjectA();
}
class ObjectA() {
DoMyTask() {
var objectB = GetObjectB();
var objectC = GetObjectC();
objectC.DoAnotherTask(); // I am assuming that you would call the doXXX or doYYY methods on objectB or C because otherwise there is no need to create them
}
void GetObjectC() {
return If_All_Is_Well_Again ? new ObjectC() : new EmptyObjectC();
}
}
class EmptyObjectA() { // http://en.wikipedia.org/wiki/Null_Object_pattern
DoMyTask() {
doZZZZ();
}
}
class ObjectC() {
DoAnotherTask() {
doXXX();
}
}
class EmptyObjectB() {
DoAnotherTask() {
doYYY();
}
}
In second case do it the same was as first.
In the third case -
var myCriteria = GetCriteria();
if(myCriteria.Contains(curretnCase))
doStuff();
IEnumerable<Names> GetCriteria() {
// return new list of criteria.
}
I'm not a C# programmer, but I will take a stab at it.
In the first case I would say that the objects should not be null in the first place. If this is unavoidable (it is usually avoidable) then I would use the early return pattern:
if ( objectA == NULL ) {
return;
}
// rest of code here
The second case is obviously not realistic code, but I would at least rather say:
if ( isTrue && e > 1 ) {
DoStuff();
}
rather than use two separate ifs.
And in the last case, I would store the strings to be tested in an array/vector/map and use that containers methods to do the search.
And finally, although using cyclomatic complexity is "a good thing" (tm) and I use it myself, there are some functions which naturally have to be a bit complicated - validating user input is an example. I often wish that the CC tool I use (Source Monitor at http://www.campwoodsw.com - free and very good) supported a white-list of functions that I know must be complex and which I don't want it to flag.
The last if in case 2 can be simplified:
if(isTrue)
{
if(e > 1)
{
can be replaced by
if(isTrue && (e>1))
case 3 can be rewritten as:
new string[]{StringConstants.AAA,...}
.Contains(e.PropertyName)
you can even make the string array into a HashSet<String> to get O(1) performance.
I have a property in my class that can only be one of several values, what is the best way to limit the input on this property.
Here is what I'm doing now, and I'm sure there must be a better way.
public void SetValue(int value)
{
if(value != 1 ||
value != 4 ||
value != 8 ||
value != 16 ||
value != 32 ||
value != 64, ||
value != 128)
{
property_value = 1;
}
else
{
property_value = value;
}
}
Instead of in int, use an Enum with these values.
I am sure each value has a specific meaning - expose these as enum members.
This may not eliminate all issues (since an Enum is simply a wrapper over an integer type and can still get assigned a value that doesn't exist in the enumeration), but should take care of most problems, so long as you are consistent about only passing values from the enumeration itself.
In any rate, you can then simply test the passed in value against the enumeration and throw an exception if it isn't a valid member.
Use enum instead of this numeric values like:
enum Numbers { Name1 = 1, Name2 = 4 ... }
and then you can easilly check if value is one of enum element:
Enum.IsDefined(typeof(Numbers), value );
For your example, you can just do:
property_value = 1;
since your if condition will always be true.
If you want to restrict it to a number of possibilities you could:
Declare an enum:
public enum Value
{
Default = 1,
Option1 = 4,
...
}
or have a collection of valid values to check:
int[] validValues = new int[] { 1, 4, 8, 16, 32, 64, 128 };
property_value = validValues.Contains(value) ? value : 1;
Although I would prefer to throw an exception on invalid input.
I think you should consider using an enum:
public enum MyEnum
{
These,
Are,
Valid,
Values
}
public void SetValue(MyEnum _value)
{
// Only MyEnum values allowed here!
}
if(((value & (value − 1)) == 0) && value != 2 && value <= 128)
property_value = 1;
else
property_value = value;
(value & (value − 1)) is a fast way to check if value is a power of two.
As an example: value = 4:
(4(10) & (3(10)) =
100(2) & 011(2) =
000(2) = 0
value = 5
(5(10) & (4(10)) =
101(2) & 100(2) =
100(2) =
4
You could use an enum and check using Enum.IsDefined(value). But then you'd have to think of a (meaningfull) name for all the possible values.
I think we're missing the INTENT of the function here.
It looks like a bit mask check to me. If that's the case, he's missing 2 from the code sample. Also, note that he's not discarding a value if it isn't one of those specific bits: he preserves it. If it is a value equal to a specific bit (and only that bit) he coerces it to 1.
I think the sample provided by Lee works best in this case; it's simple and to the point. Also, if the check is widened to account for 16 bits (or even 32), it will easily catch them all.