I have code that's very messy with the if - else if checks it is doing. The amount of branching and nested branching is quite big (over 20 if - else if and nested too). It's making my code harder to read and will probably be a performance hog. My application checks for a lot of conditions it gets from the user and so the application must check all the time for different situations, for example:
If the textbox text is not 0, continue with the next...
if ((StartInt != 0) && (EndInt != 0))
{
And then here it checks to see whether the user have choosen dates:
if ((datePickerStart.SelectedDate == null) || (datePickerEnd.SelectedDate == null))
{
MessageBox.Show("Please Choose Dates");
}
Here, if the datepickers aren't null it continues with code...
else if ((datePickerStart.SelectedDate != null) && (datePickerEnd.SelectedDate != null))
{
// CONDITIONS FOR SAME STARTING DAY AND ENDING DAY.
if (datePickerStart.SelectedDate == datePickerEnd.SelectedDate)
{
if (index1 == index2)
{
if (StartInt == EndInt)
{
if (radioButton1.IsChecked == true)
{
printTime3();
}
else
{
printTime();
}
}
This is just a small part of the checks being made. Some of them are functionals and some are for input validation stuff.
Is there any way to make it more readable and less of a performance hog?
It's not that of a performance hog. A great blog post on how to fix those common problems is Flattening Arrow Code.
I see here some mix in validation. Try to move one fields from others, and validate them separately, something like this:
if (StartInt == 0 || EndInt == 0)
{
MessageBox.Show("Please Choose Ints");
return;
}
if (datePickerStart.SelectedDate == null || datePickerEnd.SelectedDate == null)
{
MessageBox.Show("Please Choose Dates");
return;
}
In this approach you'll always say to the user what he did wrong, and your code is much simpler.
More information from Jeff's blog
One way is to refactor by encapsulating complex conditions in the following way:
public bool DateRangeSpecified
{
get
{
return (datePickerStart.SelectedDate != null)
&&
(datePickerEnd.SelectedDate != null)
&& StartInt != 0 && EndInt != 0;
}
}
and then using these "condition facade" properties
Some slight refactoring makes it easier to read to my eyes. I removed extraneous brackets and consolidated multiple IF statements that are really just AND logic.
if (StartInt == 0 || EndInt == 0)
return;
if (datePickerStart.SelectedDate == null || datePickerEnd.SelectedDate == null)
{
MessageBox.Show("Please Choose Dates");
return;
}
if (datePickerStart.SelectedDate != null
&& datePickerEnd.SelectedDate != null
&& datePickerStart.SelectedDate == datePickerEnd.SelectedDate
&& index1 == index2
&& StartInt == EndInt)
{
if (radioButton1.IsChecked == true)
printTime3();
else
printTime();
}
You can define your own predicates or generic functions with meaningful names and encapsulate you logic into those.
Here is a code example for some predicates:
public Predicate<DateTime> CheckIfThisYear = a => a.Year == DateTime.Now.Year;
public Func<DateTime, int, bool> CheckIfWithinLastNDays = (a, b) => (DateTime.Now - a).Days < b;
Now you can easily write in your code
if (CheckIfThisYear(offer) && CheckIfWithinLastNDays(paymentdate,30)) ProcessOrder();
Consider using generic delegates, like Func<> and Delegate<> for writing small blocks of your conditions using lambda-expressions -- it will both save the space and makes your code much more human-readable.
Use the return statement to stop the execution of a block.
For instance,
void Test()
{
if (StartInt==0 || EndInt==0)
{
return;
}
if (datePickerStart.SelectedDate == null || datePickerEnd.SelectedDate == null)
{
MessageBox.Show("Please Choose Dates");
return;
}
}
Related
Please check the code below. On first if section however all my conditions get false it's not going to else. Its always running the if inside codes.
To be more specific ViewBag.gtQuickDate this viewbag does not contain any value as shown below also other viewbags does not contain the value, then why it's not running the else if? Any mistake you found on operator then let me know.
if (ViewBag.subcattxt != "" & ViewBag.callFrom == "result" &
ViewBag.gtQuickDate != "2015y" || ViewBag.gtQuickDate != "2016y" ||
ViewBag.gtQuickDate != "2017y" || ViewBag.gtQuickDate != "blank")
{
}
else if (ViewBag.subcattxt != "" & ViewBag.callFrom == "result" &
ViewBag.gtQuickDate == "2015y" || ViewBag.gtQuickDate == "2016y" ||
ViewBag.gtQuickDate == "2017y" || ViewBag.gtQuickDate != "blank")
{
}
The reason for the condition evaluating incorrectly is that || has lower precedence than &, so any match of gtQuickDate renders the entire condition true.
It is generally a very bad idea to embed the current year into code, because it stops working as expected after a set period of time, requiring a recompile.
If you are looking for gtQuickDate from the last three years, you can do it like this:
int yearNow = DateTime.Now.Date.Year;
var blankOrLastThreeYears = new[] {
"blank"
, $"{yearNow - 0}y"
, $"{yearNow - 1}y"
, $"{yearNow - 2}y"
};
Now your condition can be rewritten as
if (ViewBag.subcattxt != ""
&& ViewBag.callFrom == "result"
&& blankOrLastThreeYears.Contains(ViewBag.gtQuickDate)) {
...
}
The list in blankOrLastThreeYears will contain entries for the last three years, and will update automatically for 2018, 2019, and so on.
I'm not certain what you're checking,if possible, could you separate ORs from ANDs, but please try:
if ((!(ViewBag.subcattxt.Equals(null)) && (!(ViewBag.callFrom.Equals("result"))) && (!(ViewBag.gtQuickDate.Equals("2015y"))))
{
//some other code
}
else if((!(ViewBag.gtQuickDate.Equals("2016y")) || (!(ViewBag.gtQuickDate.Equals("2017y")) || (!(ViewBag.gtQuickDate.Equals("blank"))))
{
//some other code
}
else if (ViewBag.subcattxt.Equals(null) && ViewBag.callFrom.Equals("result") && ViewBag.gtQuickDate.Equals("2015y"))
{
//some other code
}
else if(ViewBag.gtQuickDate.Equals("2016y") || ViewBag.gtQuickDate.Equals("2017y") || ViewBag.gtQuickDate.Equals("blank"))
{
//other code
}
Hope this helps.
I am stuck on what I thought would be a really easy problem. I am trying to redirect a user to a different website if the UserAgent does not contain a series of strings. The part I can not figure out is that the if statement works fine if I use the code below. I am happy with the results with this but something tells me that it is not good practice to only have an else statement and perform nothing if the statement proves to be true.
string strUserAgent = Request.UserAgent.ToString().ToLower();
if (strUserAgent != null)
{
if (Request.Browser.IsMobileDevice == true ||
strUserAgent.Contains("iphone") ||
strUserAgent.Contains("blackberry") ||
strUserAgent.Contains("mobile") ||
strUserAgent.Contains("windows ce") ||
strUserAgent.Contains("opera mini") ||
strUserAgent.Contains("palm") ||
strUserAgent.Contains("android"))
{
// Is this normal practice to only have an else block?
}else
{
Response.Redirect(AppState["redirectBack"].ToString());
}
When I try the next block of code the script redirects the user no matter what the UserAgent string contains. Can someone explain why this might be happening?
string strUserAgent = Request.UserAgent.ToString().ToLower();
if (strUserAgent != null)
{
if (Request.Browser.IsMobileDevice != true ||
!strUserAgent.Contains("iphone") ||
!strUserAgent.Contains("blackberry") ||
!strUserAgent.Contains("mobile") ||
!strUserAgent.Contains("windows ce") ||
!strUserAgent.Contains("opera mini") ||
!strUserAgent.Contains("palm") ||
!strUserAgent.Contains("android"))
{
Response.Redirect(AppState["redirectBack"].ToString());
}
You need De Morgan's Law. When you inverted your condition, your ORs need to become ANDs
Invert your statement using ! ("not"):
if(!(conditions)) { }
This will avoid the need to use an empty code block and you can just drop the else.
Your second codeblock will redirect when you're not on a mobile device or when your useragent contains any of the following strings. It depends on your input and your environment.
Do note that it's a lot easier to create a collection of the possibilities and check if your useragent is in there:
if(new[] {"iphone", "somephone", "otherphone" }.Any(x => useragent.Contains(x))) {}
It will always be true that at least one of your conditions will not be true. For instance, if strUserAgent.Contains(iphone) will be false if strUserAgent.Contains("blackberry") is true.
You need to change your OR (||) operator to a logical AND (&&) operator.
if (strUserAgent != null)
{
if (Request.Browser.IsMobileDevice != true &&
!strUserAgent.Contains("iphone") &&
!strUserAgent.Contains("blackberry") &&
!strUserAgent.Contains("mobile") &&
!strUserAgent.Contains("windows ce") &&
!strUserAgent.Contains("opera mini") &&
!strUserAgent.Contains("palm") &&
!strUserAgent.Contains("android"))
{
Response.Redirect(AppState["redirectBack"].ToString());
}
Not an answer, just a suggestion. You can make your code cleaner with an extension method:
public static bool ContainsAnyOf(this string source, params string[] strings)
{
return strings.Any(x => source.Contains(x));
}
And now write
if (strUserAgent.ContainsAnyOf("iphone", "blackberry", "mobile", "windows ce", "opera mini", "palm", "android"))
{
//
}
You need to reverse the entire thing. Putting !A || !B is not the same as !(A||B). In the first one if its A then it's Not B so it's True. In the second one it's False.
if (!(Request.Browser.IsMobileDevice == true ||
strUserAgent.Contains("iphone") ||
strUserAgent.Contains("blackberry") ||
strUserAgent.Contains("mobile") ||
strUserAgent.Contains("windows ce") ||
strUserAgent.Contains("opera mini") ||
strUserAgent.Contains("palm") ||
strUserAgent.Contains("android")
) )
{
Response.Redirect(AppState["redirectBack"].ToString());
}
string strUserAgent = Request.UserAgent.ToString().ToLower();
if (strUserAgent != null)
{
if (!(Request.Browser.IsMobileDevice == true ||
strUserAgent.Contains("iphone") ||
strUserAgent.Contains("blackberry") ||
strUserAgent.Contains("mobile") ||
strUserAgent.Contains("windows ce") ||
strUserAgent.Contains("opera mini") ||
strUserAgent.Contains("palm") ||
strUserAgent.Contains("android")))
{
Response.Redirect(AppState["redirectBack"].ToString());
}
We're trying to optimize some of our methods. We use Redgate's Performance profiler to find some performance leaks.
Our tool uses Linq to objects in several methods. But we have noticed that a FirstOrDefault takes very long on collections with +/- 1000 objects.
The profiler also alerts that the query is very slow. I've added images with the profiler results.
It's not possible to add the collection to a database and then query the database.
Any recommendations?
Thanks !
private SaldoPrivatiefKlantVerdeelsleutel GetParentSaldoPrivatiefKlantVerdeelsleutel(SaldoPrivatiefKlantVerdeelsleutel saldoPrivatiefKlantVerdeelsleutel, SaldoGebouwRekeningBoeking boeking, int privatiefKlant)
{
SaldoPrivatiefKlantVerdeelsleutel parentSaldoPrivatiefKlantVerdeelsleutel = null;
if (saldoPrivatiefKlantVerdeelsleutel != null)
{
try
{
parentSaldoPrivatiefKlantVerdeelsleutel = saldoPrivatiefKlantVerdeelsleutel.AfrekenPeriode.SaldoPrivatiefKlantVerdeelsleutelCollection
.FirstOrDefault(s => (boeking == null || (s.SaldoVerdeelsleutel != null &&
(s.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID == boeking.SaldoGebouwRekeningVerdeling.SaldoGebouwRekening.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID)))
&& s.PrivatiefKlant.ID == privatiefKlant);
}
catch (Exception ex)
{ }
}
return parentSaldoPrivatiefKlantVerdeelsleutel;
}
Image :
Profile report
You should be able to speed it up by rewriting it as
saldoPrivatiefKlantVerdeelsleutel.AfrekenPeriode.SaldoPrivatiefKlantVerdeelsleutelCollection
.Where(s => (boeking == null || (s.SaldoVerdeelsleutel != null &&
(s.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID == boeking.SaldoGebouwRekeningVerdeling.SaldoGebouwRekening.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID))) && s.PrivatiefKlant.ID == privatiefKlant)
.FirstOrDefault()
See Why is LINQ .Where(predicate).First() faster than .First(predicate)? for why this is faster.
I'll say that this
boeking.SaldoGebouwRekeningVerdeling.SaldoGebouwRekening.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID
could be the culprit. Try caching it outside, like:
var id = boeking != null ? boeking.SaldoGebouwRekeningVerdeling.SaldoGebouwRekening.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID : 0;
and use the id inside the query.
(I'm doing a supposition: one of the properties of that long chain do something "not too much smart" and is in fact quite slow)
FirstOrDefault do standard linear search over source collection and returns first element that matches a predicate. It's O(n), so it's not surprising that it takes more time on bigger collections.
You can try following, but the gain won't be huge, because it's still O(n).
private SaldoPrivatiefKlantVerdeelsleutel GetParentSaldoPrivatiefKlantVerdeelsleutel(SaldoPrivatiefKlantVerdeelsleutel saldoPrivatiefKlantVerdeelsleutel, SaldoGebouwRekeningBoeking boeking, int privatiefKlant)
{
SaldoPrivatiefKlantVerdeelsleutel parentSaldoPrivatiefKlantVerdeelsleutel = null;
if (saldoPrivatiefKlantVerdeelsleutel != null)
{
try
{
var query = saldoPrivatiefKlantVerdeelsleutel.AfrekenPeriode
.SaldoPrivatiefKlantVerdeelsleutelCollection
.Where(s => s.PrivatiefKlant.ID == privatiefKlant);
if(boeking != null)
{
var gebouwVerdeelSleutelId = boeking.SaldoGebouwRekeningVerdeling
.SaldoGebouwRekening
.SaldoVerdeelsleutel
.GebouwVerdeelSleutel
.ID;
query = query.Where(s => s.SaldoVerdeelsleutel != null &&
s.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID == gebouwVerdeelSleutelId);
}
parentSaldoPrivatiefKlantVerdeelsleutel = query.FirstOrDefault();
}
catch (Exception ex)
{ }
}
return parentSaldoPrivatiefKlantVerdeelsleutel;
}
It will make better, because boeking != null check will be done only once, not on every source collection element. And because nested Where calls are combined they will not cause performance penalty.
You can try write it like a simple code. LINQ is using delegates this is why there is a little perfomance hit.
try
{
parentSaldoPrivatiefKlantVerdeelsleutel = null;
foreach (var s in saldoPrivatiefKlantVerdeelsleutel.AfrekenPeriode.SaldoPrivatiefKlantVerdeelsleutelCollection)
{
if ((boeking == null || (s.SaldoVerdeelsleutel != null && (s.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID == boeking.SaldoGebouwRekeningVerdeling.SaldoGebouwRekening.SaldoVerdeelsleutel.GebouwVerdeelSleutel.ID))) && s.PrivatiefKlant.ID == privatiefKlant)
{
parentSaldoPrivatiefKlantVerdeelsleutel = s;
break;
}
}
}
catch (Exception ex)
{ }
take a look at the following code :
if( down == null || down.GetFace() != Face.None || down.GetFace() != Face.Partial )
{
// I called GetFace() two times
// How can i avoid to call it two times, and still putting inside that if
}
Thank you!
To be more maintainable and expressive first separate the null check as exceptional case
then get the result to a variable and check it.
if(down == null)
// Some exceptional case .. return or throw exception
var result = down.GetFace();
if(result == Face.None || result != Face.Parial)
// Do your code here
Refactor to a method:
private bool IsFaceNoneOrPartial(Down down)
{
var face = down.GetFace();
return face != Face.None || face != Face.Partial;
}
// Your code is now:
if( down == null || IsFaceNoneOrPartial(down))
{
}
i wanted to try the following code:
//all arrays are List<T> type.
if (m.terms[0] != null && m.terms[0].labels != null && m.terms[0].labels[0].title == "Part-of-speech")
{
result = true;
}
but it occured runtime error occasionly in following situation
i. m.terms == null
ii. m.terms != null, but m.terms[0] does not intialized.
iii. m.terms != null, and m.terms[0] has been exist but
m.terms[0].label does not initialized.
...
so i did modify it to like this:
if (m.terms[0] != null)
{
if (m.terms[0].labels != null)
{
if (m.terms[0].labels[0].title == "Part-of-speech") { result = true; }
}
}
is it the best way?
&& is a short circuiting operator, so the first way you wrote it and the second way will be functionally equivalent.
if (a && b && c)
{
// work
}
b will only be evaluated if a returns true. (Same goes for c).
In your code, checking m.terms[0].labels will not be a problem because you would have short-circuited out of the expression if m.terms[0] had been null.
To completely cover yourself, you'd want to possibly add checks for m and m.terms, however.
m != null && m.terms != null && m.terms.Count > 0 && m.terms[0] != null ...
As it evaluates from left to right, it will break on the first condition that doesn't pass and the rest will go unchecked.
int index = 0;
int labelIndex = 0;
string titleToCheck = "Part-of-speech";
if (m != null && m.terms != null && m.terms.Count > index)// or m.Length...
{
if (m.terms[index] != null && m.terms[index].labels != null &&
m.terms[index].labels.Count > labelIndex)
{
if (m.terms[index].labels[labelIndex].title == titleToCheck)
{
result = true;
}
}
}
This is all about readability. C# uses Short-circuit evaluation so in functionality there is no difference.
try this
if (m!=null && m.terms!= null && m.terms[0].labels!=null && m.terms[0].labels[0].title!=null && m.terms[0].labels[0].title == "Part-of-speech")
Yes, it would be better to split off each null check into a separate if statement.
The reason is that the second and third conditions require the first to not be null. If the first is null, then the second and third conditions will in turn throw errors because their parent is null yet is trying to be accessed.