Let me start by saying that I have read up on my problem, specifically this question and this one also. My problem is a little different, however. I understand the differences between the different methods, but cannot get my code to run correctly for the life of me.
In part of my code, I have the comparison below. But the comparison always fails, and "Type is:leg" prints out.
if (String.Compare(timer.Type,"leg",true) == 0)
{
timer.StopTime = DateTime.Now;
// TODO Log into database here
toRemove.Add(timer);
}
//Couple more conditions in here...
else
{
Console.WriteLine("Attempting to remove cycle timer of invalid type");
Console.WriteLine("Type is:" + timer.Type);
//TODO: Log error
}
I also tried alternative methods, but none of them seem to work for me.
if(timer.Type == "leg" || timer.Type == "Leg") //Fails
if(time.Type.Equals("leg") || timer.Type == "Leg") //Fails
String type = timer.Typer; //Worth a shot...
if(type == "leg" || type == "Leg") //No luck
EDIT: More code has been requested, so here is the entire method.
private void stopFinishedTimers(AGVData agv)
{
List<CycleTimer> toRemove = new List<CycleTimer>();
foreach (CycleTimer timer in AllRunningCycleTimers)
{
if (agv.CurrentRFIDNumber == timer.CycleStopRfid)
{
if (String.Compare(timer.Type,"leg",true) == 0)
{
timer.StopTime = DateTime.Now;
// TODO Log into database here
toRemove.Add(timer);
}
else if (timer.Type.Equals("route") || timer.Type.Equals("Route"))
{
timer.StopTime = DateTime.Now;
// TODO Log into database here
toRemove.Add(timer);
}
else
{
Console.WriteLine("Attempting to remove cycle timer of invalid type");
Console.WriteLine("Type is:" + timer.Type);
//TODO: Log error
}
}
}
Where CycleTimers are a class containing a fields called type, accessed through a property.
I'll add my two cents:
The line String type = timer.Typer seems wrong because the property name is Type in most of your examples. Also if(time.Type.Equals("leg") || timer.Type == "Leg") seems suspicious since you are referencing time and timer instead of the same variable both times.
Lastly, I always always use StringComparison.Ordinal when comparing strings in .Net because of culture info and character set differences, etc. I'm not sure if that could be an issue but see this for more information.
EDIT:
On a side note, StringComparison.OrdinalIgnoreCase is also an option.
Debug and put a break statement to see what timer.Type equates to, or put a Console.WriteLine(timer.Type.ToString())... Could timer have gone out of scope?
or maybe change the test to timer.Type.ToString() == "Leg"
Related
I'm currently attempting to validate a string for an assignment so it's imperative that I'm not simply given the answer, if you provide an answer please give suitable explanation so that I can learn from it.
Suppose I have a string
(1234)-1234 ABCD
I'd like to create a loop that will go through that string and validate the position of the "()" as well as the "-" and " ". In addition to the validation of those characters their position must also be the same as well as the data type. Finally, it must be inside a method.
CANNOT USE REGEX
TLDR;
Validate the position of characters and digits in a string, while using a loop inside of a method. I cannot use REGEX and need to do this manually.
Here's what I have so far. But I feel like the loop would be more efficient and look nicer.
public static string PhoneChecker(string phoneStr)
{
if (phoneStr[0] == '(' && phoneStr[4] == ')' && phoneStr[5] == ' ' && phoneStr[9] == '-' && phoneStr.Length == 14)
{
phoneStr = phoneStr.Remove(0, 1);
phoneStr = phoneStr.Remove(3, 1);
phoneStr = phoneStr.Remove(3, 1);
phoneStr = phoneStr.Remove(6, 1);
Console.WriteLine(phoneStr);
if (int.TryParse(phoneStr, out int phoneInt) == false)
{
Console.WriteLine("Invalid");
}
else
{
Console.WriteLine("Valid");
}
}
else
{
Console.WriteLine("Invalid");
}
return phoneStr;
}
It is still unmaintaible, but still a little better... Note that your code didn't work with your example string (the indexes were off by one).
public static bool PhoneChecker(string phoneStr)
{
if (phoneStr.Length != 16 || phoneStr[0] != '(' || phoneStr[5] != ')' || phoneStr[6] != '-' || phoneStr[11] != ' ')
{
return false;
}
if (!uint.TryParse(phoneStr.Substring(1, 4), out uint phoneInt))
{
return false;
}
if (!uint.TryParse(phoneStr.Substring(7, 4), out phoneInt))
{
return false;
}
// No checks for phoneStr.Substring(12, 4)
return true;
}
Some differences:
The Length check is the first one. Otherwise a short string would make the program crash (because if you try to do a phoneStr[6] on a phoneStr that has a length of 3 you'll get an exception)
Instead of int.Parse I used uint.Parse, otherwise -500 would be acceptable.
I've splitted the uint.Parse for the two subsections of numbers in two different check
The method returns true or false. It is the caller's work to write the error message.
There are various school of thought about early return in code: I think that the earlier you can abort your code with a return false the better it is. The other advantage is that all the remaining code is at low nesting level (your whole method was inside a big if () {, so nesting +1 compared to mine)
Technically you tagged the question as C#-4.0, but out int is C#-6.0
The main problem here is that stupid constraints produce stupid code. It is rare that Regex are really usefull. This is one of the rare cases. So now you have two possibilities: produce hard-coded unmodifiable code that does exactly what was requested (like the code I wrote), or create a "library" that accepts variable patterns (like the ones used in masked edits, where you can tell the masked edit "accept only (0000)-0000 AAAA") and validates the string based on this pattern... But this will be a poor-man's regex, only worse, because you'll have to maintain and test it. This problem will become clear when one month from the release of the code they'll ask you to accept even the (12345)-1234 ABCD pattern... and then the (1234)-12345 ABCD pattern... and a new pattern every two months (until around one and half years later they'll tell you to remove the validator, because the persons that use the program hate them and it slow their work)
I have a function that calls a lot of other functions from different objects. Each function has to return true before calling the next one. As you can see I am using too many if statements. How can I improve the code and make it neater? Thanks
bool ISOKToDoSomthing()
{
boo retVal = false;
retVal = ObjA.CheckVersion(oldVersion);
if(retVal)
{
retVal = objB.CheckUserRight();
}
if(retVal)
{
retVal = ObjC.ISDBExist();
}
if(retVal)
{
retVal = OjbD.ISServerUp(ServerName);
}
//tons of similar code as above
.........
return retVal;
}
return
ObjA.CheckVersion(oldVersion) &&
objB.CheckUserRight() &&
ObjC.ISDBExist() &&
OjbD.ISServerUp(ServerName);
My advice: do nothing to this code without a clear business case for making the change.
Your code is clear, obvious, likely correct, easy to maintain and easy to debug. Why on earth would you want to change it in any way? Spend your time adding value by fixing bugs and adding features, not by changing working code unnecessarily. When your boss asks you "so what did you do today?" the answer should not be "I increased our schedule risk to by making unnecessary cosmetic changes to correct, working, already-debugged code".
Now, if there really is a problem here, the problem is likely not that the code is hard to read, but rather that the code rigidly encodes what ought to be a user-configurable business process. In that case, create an object called "Workflow" that encodes the business process, and an engine which evaluates an arbitrary workflow. Then construct an instance of that object that represents the desired workflow based on input from the user.
That actually adds value for the user; the user cares not a bit whether you use nested "if" statements or not.
if (!ObjA.CheckVersion(oldVersion)) return false;
if (!ObjB.CheckUserRight()) return false;
if (!ObjC.IsDBExist()) return false;
if (!ObjD.IsServerUp(serverName)) return false;
... your other checks ...
return true;
The short-circuiting of && is useful for a few conditions, but if you have "tons" of them, IMO that's way too much to try and stick in one statement.
A combination of the two might be useful, though. More useful still would be to condense some of these checks together into bigger chunks (but smaller than IsOKToDoSomething). For instance, check whether you have access to the database (whether it exists, whether you can log in to it, etc) all at once
Truth be told, the fact that you have so many objects to check hints at a design issue -- namely, you're trying to do too much at once, or you have a "god object" somewhere that has its little tentacles in every aspect of the system. You might want to look at fixing that.
return ObjA.CheckVersion(oldVersion) && objB.CheckUserRight() && ObjC.ISDBExist() && OjbD.ISServerUp(ServerName)
The && operator will short-circuit, so you can chain them like so:
bool ISOKToDoSomthing()
{
return
ObjA.CheckVersion(string oldVersion) &&
objB.CheckUserRight() &&
ObjC.ISDBExist() &&
OjbD.ISServerUp(ServerName) &&
//tons of similar code as above
.........
}
bool ISOKToDoSomthing()
{
return ObjA.CheckVersion(string oldVersion) &&
ObjB.CheckUserRight() &&
ObjC.ISDBExist() &&
OjbD.ISServerUp(ServerName);
}
Perhaps?
retVal = objB.CheckUserRight() && ObjC.ISDBExist() && OjbD.ISServerUp(ServerName);
etc.
A side note, you can test for example, if objB is null before calling a method on it in one statement (the code will break execution as soon as a condition has not been met, i.e. won't call the next condition) so you don't need lots of if(objB != null) type statements. E.g.:
retVal = (objB != null && objB.CheckUserRight()) && (ObjC != null && ObjC.ISDBExist()) && (OjbD != null && OjbD.ISServerUp(ServerName));
You can leverage the fact that C# does short-circuit evaluation:
return
ObjA.CheckVersion(oldVersion) &&
objB.CheckUserRight() &&
ObjC.ISDBExist() &&
OjbD.ISServerUp(ServerName);
Editing to fix syntax on CheckVersion's parameters
How about using and:
retVal = ObjA.CheckVersion(oldVersion) &&
objB.CheckUserRight() &&
ObjC.ISDBExist() &&
OjbD.ISServerUp(ServerName);
return retval;
To make the code less wordy, you could try a while loop. Given that your method here is to not ever change the value of your original value if it /ever/ turns false, then it would be while(retval) {} and iterate over a list of actions. Personally, I think this is ugly. Consider using a switch, or even (yuck on this, but it would work) a bitwise enum.
From my perspective, when I see myself writing code like this, I've made a grave architectural mistake somewhere and I should really rethink the reason behind making this call. Perhaps you should take another look at your logic, rather than just your code. Sit down and draw some boxes and work a bit more in the design phase and you might find yourself building things very differently.
edit: or yeah, like everyone else did, you can make your iteration a single if statement. Again, this is a bigger problem than a long list of booleans.
It depends on how much you want to change. Perhaps instead of returning a bool from your sub-methods, you could throw an exception.
bool retVal = true;
try
{
ObjA.CheckVersion(oldVersion);
objB.CheckUserRight();
ObjC.ISDBExist();
OjbD.ISServerUp(ServerName);
}
catch (SomeException ex)
{
// Log ex here.
retVal = false;
}
return retVal;
If you do something like this, IsDBExist probably isn't the best name (since Is generally translates to "returns a bool" in my mind), but you get the picture.
Working on parsing from a text box to int to get into the incrementHour method as shown.
if (txtHourPlus.Text != String.Empty)
{
time1.incrementHour(int.Parse(txtHour.Text));
}
And in the time class: (the time1 objects class)
public int incrementHour(int step)
{
if (step > 0 && hour < 24)
{
//step = step % hour;
hour = (hour + step) % 24;
time.AddHours(hour);
return hour;
}//end of if
else
{
MessageBox.Show("Please enter a positive number.");
return 0;
}//end of else
}//end of incrementHour
not sure why i'm getting this error. I'm converting it to the corrent data type. Because it accepts an int variable.
Alright well i got it to take the value (small mistake >.> Don't even wanna say it)
However as someone already said the method probably needs work because i'm trying to change the Datetime value that i get in the first place and add an hour or subtract and etc etc.
That will happen if someone has typed "foo" into the text box, for example. You should use int.TryParse instead, which lets you detect the error without an exception being thrown.
I notice that you're not actually using the return value of your method though - just like you're not using the return value of time.AddHours. You are aware that DateTime.AddHours doesn't actually modify the value you're calling it on, aren't you? (I suspect you'll need to tweak that method quite a bit, actually... there are various potential problems with it, depending on exact what you're trying to do.)
(Finally, I'd change the method name to IncrementHour to comply with .NET conventions.)
you are testing txtHourPlus for emptiness, but then parsing and passing txtHour. typo (?)
If your input isn't parsable as an integer, attempting to parse it will raise an exception. Validate or use Int32.TryParse()
Change this part of your code:
if (txtHour.Text != String.Empty)
{
int parsedValue;
if (int.TryParse(txtHour.Text, out parsedValue))
{
time1.incrementHour(parsedValue);
}
else
{
// non-numeric value was entered into the textbox - handle accordingly.
}
}
The code below looked ok to me when I wrote it, but when I came back to it again, it was pretty hard to grasp what is going on. There used to be parenthesis around value == ..., but I had to remove them after StyleCop became mandatory (I cannot really control this). So, how can I improve this section of code? I was thinking: x = value == y ? true : false;, but that probably is even more confusing, plus silly, although compiler will optimize that.
set
{
Debug.Assert(value == ConfigType.DATABASE || value == ConfigType.FILE,
"Configuration type must be either 'File-based' or 'Database-based'; it was: "
+ value.ToString());
// HG TODO: The following is concise but confusing.
this.fileBasedRadioButton.Checked = value == ConfigType.FILE;
this.databaseBasedRadioButton.Checked = value == ConfigType.DATABASE;
}
bool isFile = value == ConfigType.FILE;
bool isDatabase = value == ConfigType.DATABASE; // or isDatabase = !isFile
Debug.Assert(isFile || isDatabase,
"Configuration type must be either 'File-based' or 'Database-based'; it was: "
+ value.ToString());
this.fileBasedRadioButton.Checked = isFile;
this.databaseBasedRadioButton.Checked = isDatabase;
This makes it a little more readable (explicitly declaring the bool), you know it has to be true or false.
And this way, if you need to (maybe in the future) change settings based on file/database in the same method, you already have the bool handy, instead of checking each time
If you don't want to use the ?: operator use if..else. Sure it is a little more verbose, but you wont spend more than a few seconds figuring it out.
A few months from now when you revisit this code you will be glad you took an extra 5 lines.
Making code easy to maintain should be your #1 priority.
if (value == ConfigType.FILE)
this.fileBasedRadioButton.Checked = true;
else
this.fileBasedRadioButton.Checked = false;
if (value == ConfigType.DATABASE)
this.databaseBasedRadioButton.Checked = true;
else
this.databaseBasedRadioButton.Checked = false;
Indent the second and third line of the Debug.Assert() method. It should then look like this:
Debug.Assert(value == ConfigType.DATABASE || value == ConfigType.FILE,
"Configuration type must be either 'File-based' or 'Database-based'; it was: "
+ value.ToString());
I know this is really a minor stylistic alteration, but I've always found when I have to pass a lot of arguments or have some really long statement, when I carry over to a newline I should indent before the ;.
It prevents the Debug.Assert() from looking like 3 lines.
As for the value==, I agree with the previous poster. You should make a bool isDatabase and isFile to prevent calling a field from ConfigType twice in your first arg.
I came across the following expression in someone else's code. I think it's terrible code for a number of reasons (not least because it fails to take into account bool.TrueString and bool.FalseString), but am curious as to how the compiler will evaluate it.
private bool GetBoolValue(string value)
{
return value != null ? value.ToUpper() == "ON" ? true : false : false;
}
Edit
Incidentally, aren't the expressions evaluated from the inside-outwards? In this case, what's the point of checking for value != null after the call to value.ToUpper() which will throw a null reference exception?
I think the following is a correct (deliberately) verbose version (I'd never leave it like this :D ):
if (value != null)
{
if (value.ToUpper() == "ON")
{
return true;
}
else // this else is actually pointless
{
return false;
}
}
else
{
return false;
}
Which can be shortened to:
return value != null && value.ToUpper == "ON";
Is this a correct re-writing of the expression?
It looks like the method is indended to handle a value that comes from a checkbox HTML element. If no value is specified for the checkbox, it uses the value "on" by default. If the checkbox is not checked there is no value at all from it in the form data, so reading the key from Request.Form gives a null reference.
In this context the method is correct, althought it's quite horrible due to the use of the if-condition-then-true-else-false anti-pattern. Also it should have been given a name that is more fitting for it's specific use, like GetCheckboxValue.
Your rewrite of the method is correct and sound. As the value is not culture dependant, converting the value to uppercase should not use the current culture. So a rewrite that is even slightly better than the one that you proposed would be:
return value != null && value.ToUpperInvariant == "ON";
(The culture independent methods are also a bit faster than the ones using a specific culture, so there is no reason not to use them.)
Incidentally, aren't the expressions
evaluated from the inside-outwards?
If it was method calls so that all expressions were actually evaluated, they would, as the inner call has to be made to evaluate the parameters for the outer call.
However, the second and third operands of the conditional expression is only evaluated if they are used, so the expressions are evaluated from the outside and inwards. The outermost condition is evaluated first to decide which of the operands it will evaluate.
You are correct, both in your rewriting and in your assertion that this attempt at conciseness is bad because it leads to confusion.
well the first one is a double-nested ternary operator
return (value != null) ? [[[value.ToUpper() == "ON" ? true : false]]] : false;
The bit in [[[ ]]] is the first result of the ternary expression which gets evaluated
when the first condition is true so you're reading/assertion of it is correct
but its ugly as hell and very unreadable/unmaintainable in its current state.
I'd definitely change it to your last suggestion
SideNote:
People who do
if(X == true)
return true;
else
return false;
instead of
return X;
should be taken out and shot ;-)
Are you looking for speed or readability and organization? Speed of execution, your shortened example is probably the best way to go.
For a few extra milliseconds, you could re-write this utility method as an extension method like so:
public static bool ToBoolean(this string value)
{
// Exit now if no value is set
if (string.IsNullOrEmpty(value)) return false;
switch (value.ToUpperInvariant())
{
case "ON":
case "TRUE":
return true;
}
return false;
}
... and then you would use it as follows:
public static void TestMethod()
{
bool s = "Test".ToBoolean();
}
EDIT:
Actually, I'm wrong... a quick performance test shows that the extension method is FASTER than the inline method. The source of my test is below, as well as the output on my PC.
[Test]
public void Perf()
{
var testValues = new string[] {"true", "On", "test", "FaLsE", "Bogus", ""};
var rdm = new Random();
int RunCount = 100000;
bool b;
string s;
Stopwatch sw = Stopwatch.StartNew();
for (var i=0; i<RunCount; i++)
{
s = testValues[rdm.Next(0, testValues.Length - 1)];
b = s.ToBoolean();
}
Console.Out.WriteLine("Method 1: {0}ms", sw.ElapsedMilliseconds);
sw = Stopwatch.StartNew();
for (var i = 0; i < RunCount; i++)
{
s = testValues[rdm.Next(0, testValues.Length - 1)];
b = s != null ? s.ToUpperInvariant() == "ON" ? true : s.ToUpperInvariant() == "TRUE" ? true : false : false;
}
Console.Out.WriteLine("Method 2: {0}ms", sw.ElapsedMilliseconds);
}
Output:
Method 1: 21ms
Method 2: 30ms
I read the original expression the same way you do. So I think your shortened expression is correct. If value is null it will never get to the second conditional, so it looks safe to me.
I also hate the constructs like:
if (value.ToUpper() == "ON")
{
return true;
}
else // this else is actually pointless
{
return false;
}
as you noticed it is a long and convoluted (not to say stupid) way of writing:
return value.ToUpper() == "ON";
Your proposition is nice, short and correct.
Another alternative:
return string.Equals( value, "ON", StringComparison.OrdinalIgnoreCase );