At the top of my form I have:
public static int hoursInt;
public static int minutesInt;
public static int secondsInt;
public static int CompletedIn24;
Then further down I have the following to reset the numericUpDown boxes to zero when selecting a new runner:
private void lstRunners_SelectedIndexChanged(object sender, EventArgs e)
{
Runner selectedRunner = (Runner)lstRunners.SelectedItem;
numericUpDown1.Value = 0;
numericUpDown2.Value = 0;
numericUpDown3.Value = 0;
}
Then in the Finish button click event I have:
hoursInt = Convert.ToInt32(numericUpDown1.Value);
minutesInt = Convert.ToInt32(numericUpDown2.Value);
secondsInt = Convert.ToInt32(numericUpDown3.Value);
if (lstRunners.SelectedIndex > -1 && hoursInt + minutesInt + secondsInt != 0)
{
// Obtain selected climber
Runner selectedRunner = (Runner)lstRunners.SelectedItem;
selectedRunner.Hours = hoursInt;
selectedRunner.Minutes = minutesInt;
selectedRunner.Seconds = secondsInt;
var expertRunner = selectedRunner as Expert;
if (expertRunner != null)
{
expertRunner.UponFinish();
}
Here is my overriden method in Expert : Runner:
public override void UponFinish()
{
base.UponFinish();
// The integer must increment by one if the time is 24:00:00 or less i.e. 23:59:59 would increment the integer as well
if (Hours < 24 || (Hours == 24 && Minutes == 0 && Seconds == 0))
{
CompletedIn24++;
}
}
At present the UponFinish() method in Runner doesn't have anything inside the braces as I'm not sure if anything is required?
I tried to output the CompletedIn24 integer to a string to see if it would work when the button is clicked but the value stayed at zero even if an expert runner was selected and the time was 24:00:00 or less. The integer is not incrementing and I'm not sure what is causing the problem?
Any help would be appreciated.
Simply use the as keyword like this:
var runner = selectedRunner as Expert;
if(runner != null) runner.UponFinish();
If your class Runner already defines some method called UponFinish, you should define this method as virtual and override that method in the derived classes, like this:
public class Runner {
public virtual void UponFinish(){
//...
}
}
public class Expert : Runner {
public override void UponFinish(){
//You talked about the time, I asked for clarification on this
//but it's still very unclear. I suppose when you mean the time is 24:00:00
//that means the hours is 24, the minutes is 0 and the seconds is 0
if(Hours < 24 || (Minutes == 0 && Seconds == 0)) Completedin24++;
}
}
Then of course you don't need any cast, just call UponFinish and the overridden code (if any) will be called correctly:
selectedRunner.UponFinish();
You can check type like this:
if (selectedRunner.GetType() == typeof(Expert))
{
Expert expert = (Expert)selectedRunner;
}
You can do
if(selectedRunner is Expert)
{
UponFinish((Expert)selectedRunner);
//or ((Expert)selectedRunner).UponFinish(); if that was the intention
}
or alternatively
Expert selectedExpert = selectedRunner as Expert;
if(selectedExpert != null)
UponFinish(selectedExpert);
edit:
If your UponFinish function is already part of both Runner and Expert (that is, overridden in Expert), you don't need to cast selectedRunner before calling it.
There are several ways to do this, exists the operator is for example:
Operator IS
You can check if your Runner is an ExpertRunner by using the is keyword:
if(selectedRunner is ExpertRunner)
However, in terms of OOP you should never have to do this, you may want to check your hierarchy or logic why you need to handle this case seperately and not in overridden behaviour (function or properties).
Try this :
if(lstRunners.SelectedItem is Expert)
{
Expert selectedRunner = lstRunners.SelectedItem as Expert;
selectedRunner.UponFinish();
}
if (lstRunners.SelectedItem is Expert)
{
((Expert)lstRunners.SelectedItem).UponFinish();
}
Related
I'm new to C# but not to programming in general.
I am trying to set add some error checking to my program. There are 3 textboxes and I am trying to make it so that if the text box is left blank, it assumes a value of 0. Here is my code so far:
private void btnCalculate_Click(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(txtNumberOfClassATix.Text)) // Assumes 0 if no number entered for txtNumberOfClassATix.Text.
{
txtNumberOfClassATix.Text = "0";
}
if (String.IsNullOrEmpty(txtNumberOfClassBTix.Text)) // Assumes 0 if no number entered for txtNumberOfClassBTix.Text.
{
txtNumberOfClassBTix.Text = "0";
}
if (String.IsNullOrEmpty(txtNumberOfClassCTix.Text)) // Assumes 0 if no number entered for txtNumberOfClassCTix.Text.
{
txtNumberOfClassCTix.Text = "0";
}
int classANum = int.Parse(txtNumberOfClassATix.Text);
int classBNum = int.Parse(txtNumberOfClassBTix.Text);
int classCNum = int.Parse(txtNumberOfClassCTix.Text);
double classATotal = classANum * classAPrice;
double classBTotal = classBNum * classBPrice;
double classCTotal = classCNum * classCPrice;
lblCalculatedClassARevenue.Text = $"{classATotal:c}";
lblCalculatedClassBRevenue.Text = $"{classBTotal:c}";
lblCalculatedClassCRevenue.Text = $"{classCTotal:c}";
lblCalculatedTotalRevenue.Text = $"{(classATotal + classBTotal) + classCTotal:c}";
}
This code works but I'm sure I could replace those if statements with something simpler. I've seen how to set a variable to null if another is null using the null-conditional operator but I don't really grasp it enough to adapt it to my scenario.
So far maccettura's answer is the best, but can we do better? Sure we can. Let's make a general-purpose extension method:
internal static class Extensions
{
public static int? AsInt(this string s)
{
int result;
if (s == null)
return null;
else if (int.TryParse(s, out result))
return result;
else
return null;
}
}
And now:
int classANum = txtNumberOfClassATix.Text.AsInt() ?? 0;
If it's an int, you get the int. If it's not, you get zero. Easy peasy.
Or, you might want this extension method:
internal static class Extensions
{
public static int AsInt(this string s, int default = 0)
{
int result;
if (s == null)
return default;
else if (int.TryParse(s, out result))
return result;
else
return default;
}
}
And now you can say what you want the default to be without using ??.
This style of programming is called "fluent programming"; it can make code that is very easy to read and understand.
Notice that this solution does not update the UI with zeros; if you wanted to do that then I would recommend splitting that into two steps: one which causes the mutation, and then a separate step which computes the value. Operations which are useful for both their effects and their values can be confusing.
This is a perfect time to use a method so you arent repeating yourself:
private static int GetInputAsInt(TextBox textbox)
{
int outputValue = 0;
if(textbox?.Text != null && int.TryParse(textbox.Text, out outputValue))
{
return outputValue;
}
return 0;
}
Now you are checking if the textbox itself is not null, and that the value contained therein is a int, if anything fails it returns a 0;
Call it in your other method like this:
int classANum = GetInputAsInt(txtNumberOfClassATix);
Which means your button click event would be a bit simpler:
private void btnCalculate_Click(object sender, EventArgs e)
{
int classANum = GetInputAsInt(txtNumberOfClassATix);
int classBNum = GetInputAsInt(txtNumberOfClassBTix);
int classCNum = GetInputAsInt(txtNumberOfClassCTix);
double classATotal = classANum * classAPrice;
double classBTotal = classBNum * classBPrice;
double classCTotal = classCNum * classCPrice;
lblCalculatedClassARevenue.Text = $"{classATotal:c}";
lblCalculatedClassBRevenue.Text = $"{classBTotal:c}";
lblCalculatedClassCRevenue.Text = $"{classCTotal:c}";
lblCalculatedTotalRevenue.Text = $"{(classATotal + classBTotal) + classCTotal:c}";
}
To keep it simple, a good approach is to use the conditional operator. The full example is below (broken across two lines for readability):
txtNumberOfClassATix.Text =
String.IsNullOrEmpty(txtNumberOfClassATix.Text) ? "0" : txtNumberOfClassATix.Text;
This is a nice, readable, assignment for the first part:
myString = ...
The conditional operator breaks down by providing a boolean expression (true/ false) on the left side of the ?. So, for example:
myString = anotherString == "" ? ... // checking if another string is empty
The final part is the :. To the left is the assignment if the expression is true, and to the right goes the assignment if the expression is false. To finish the example:
myString = anotherString == "" ? "anotherString is empty" : "anotherString is not empty";
The above example can be written out in full to clear up any misunderstanding as:
if (anotherString == "")
{
myString = "anotherString is empty";
}
else
{
myString = "anotherString is not empty";
}
This can apply to all the statements. The documentation is found here.
The best way to reduce the line of code is use the function for your common operation(s). In your case, you can create function which checks whether or not the object is NULL or empty. Based on the return value of that function you can proceed ahead. On the other hand, you can handle it on front-end by using different validators such as RequiredFieldValidator, CustomValidator, etc.
I am still learning C# but I've been on annual leave and I have come back to work and seen this piece of code my senior has left me before he went on his annual leave:
public string GetBasketTotalPrice(string basketLocation)
{
var basketTotalPrice = _driver.FindElements(CommonPageElements.BasketTotalPrice);
if (basketLocation.ToLower() == "top")
return basketTotalPrice[0].Text.Replace("£", "");
else
return basketTotalPrice[1].Text.Replace("£", "");
}
private int GetElementIndexForBasketLocation(string basketLocation)
{
return basketLocation == "top" ? 0 : 1;
}
I am assuming instead of using the if else statement, he wants me to use his new method of GetElementIndexForBasketLocation.
My question is simply how to implement this change?
Thanks
It's not totally clear what you're looking for, but you can rework the code something like this:
public string GetBasketTotalPrice(string basketLocation)
{
var basketTotalPrice = _driver.FindElements(CommonPageElements.BasketTotalPrice);
int index = GetElementIndexForBasketLocation(basketLocation);
return basketTotalPrice[index].Text.Replace("£", "");
}
private int GetElementIndexForBasketLocation(string basketLocation)
{
return basketLocation.ToLower() == "top" ? 0 : 1;
}
It looks like the method he provided you isn't calling ToLower(), leaving it to the client to do that work, which could lead to mistakes down the road.
Also, you might consider using string.Equals with StringComparison.OrdinalIgnoreCase instead of ToLower.
And it might be a good idea to add a null check before trying to call a method on the string, so you can throw an ArgumentNullException instead of the NullReferenceException that the current code will throw.
public string GetBasketTotalPrice(string basketLocation)
{
var basketTotalPrice = _driver.FindElements(CommonPageElements.BasketTotalPrice);
return basketTotalPrice[GetElementIndexForBasketLocation(basketLocation)]
.Text.Replace("£", "");
}
private int GetElementIndexForBasketLocation(string basketLocation)
{
if (basketLocation == null) throw new ArgumentNullException(nameof(basketLocation));
return basketLocation.Equals("top", StringComparison.OrdinalIgnoreCase) ? 0 : 1;
}
i have a project in which i have assigned some functions to single characters(e.g. Keyboard Key "H" will do high pass filtering).
Now To get "H" as an output i have created a down event which hopefully pick up the keys are down and calls the function with an integer value. However I get an error when i try to compare the input value with an integer value in the function. The following is my code...
public static event DownEventHandler Down;
public static delegate void DownEventHandler(string Key);
Down(FunctionChar((Keys)lParam.Code)); // lParam.code is an integer value.
private string FunctionChar(Keys e)
{
if(e >=65 && e<=90){
if (Control.IsKeyLocked(Keys.CapsLock) || ((Control.ModifierKeys !=0) && (Keys.Shift) != 0))
{
return e.ToString;
}
else
{
return e.ToString.ToLower;
}
}
I assume that this function will give me the output a string either "G" or "g". as mentioned before i want to use it in further functionality.
However it gives me error as following.
Operator '>=' cannot be applied to operands of type 'System.Windows.Forms.Keys' and 'int'
I know one of the solution is to use SWITCH statement but i want to use if statement and not switch.
Can some one tell me - what is the problem? What values does "e" posses and how can i convert it to (Int) so i can use it in the IF statement.
You can't compare System.Windows.Forms.Key with and Integer so you have to convert the key has been converted to an integer before you compare them. here is an example for you:
Keys e = Keys.A;
int keyVal= (int)e;// return 65
So you can do like this:
if((int)e >=65 && (int)e<=90)
{
// your code goes here
}
Another way for doing this is:
if(e >= Keys.A&& e<= Keys.Z)
{
// your code goes here
}
Update :
You can return the corresponding character using : return ((char)e).ToString();
Hence the whole function signature will be like the following:
private string FunctionChar(Keys e)
{
if ((int)e >= 65 && (int)e <= 90)
{
if (Control.IsKeyLocked(Keys.CapsLock) || ((Control.ModifierKeys != 0) && (Keys.Shift) != 0))
{
return ((char)e).ToString();
}
else
{
return ((char)e).ToString().ToLower();
}
}
return "";
}
When working with an enum, such as Keys, it's better design to express any conditions in terms of the enum's values, rather than casting back to ints.
So I'd recommend replacing:
if(e >=65 && e<=90)
with
if (e >= Keys.A && e <= Keys.Z).
This should compile fine - and your intention is clearer to anyone reading your code!
I'd rather not use magic numbers but actual chacraters, and I'd write an extension method(s) for this:
public static class KeysExtensions
{
public static Boolean IsLetter(this Keys value)
{
return value >= Keys.A && value <= Keys.Z;
}
}
So when handling events you can put readable code:
private void Something_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode.IsLetter())
{
// Do your operations here...
}
}
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.