I have a if elseif else statement like as follows
if (check1) ---- 1
{
if(check2) ----2
{
}
}
else if (checkother1) ---- 3
{
if(checkother2) -----4
}
else ------- 5
{
do this
}
return someview
when the code hits first if statement and if the condition validates it will go inside check2 if statement after doing the validation it is entering the last else statement(5) correctly .
But when the code enters the 3rd if statement and after validating the 4th if statement if is not validated it is showing error properly but if it get validated it is directly going to the return
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("CanditateId,CanditateFirstName,CanditateLastName,CanditateAadhar,CanditatePancard,CanditateEmail,CanditateGender,CanditateLocation,CanditateMaritialStatus,CanditateDoj,CanditateActDoa,CanditateDesignation,CanditateDepartment,CanditateTeam,CanditateAddress,CanditateAltNumber,CanditateIdNumber,CanditateBaseLocation,CanditateManager,CanditatePrefix,CanditateMobile")] Canditateinfo canditateinfo)
{
var canditateinfos = await _context.Canditateinfos.FindAsync(id);
if (id != canditateinfo.CanditateId)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
var isAAdharAlreadyExists = _context.Canditateinfos.Any(x => x.CanditateAadhar == canditateinfo.CanditateAadhar);
var isPanCardAlreadyExists = _context.Canditateinfos.Any(x => x.CanditatePancard == canditateinfo.CanditatePancard);
if (canditateinfos.CanditateAadhar != canditateinfo.CanditateAadhar)
{
if (isAAdharAlreadyExists)
{
ModelState.AddModelError("CanditateAadhar", "User with this aadhar already exists");
return View(canditateinfo);
}
}
else if (canditateinfos.CanditatePancard != canditateinfo.CanditatePancard)
{
if (isPanCardAlreadyExists)
{
ModelState.AddModelError("CanditatePancard", "User with this Pan Number already exists");
return View(canditateinfo);
}
}
else
{
canditateinfo.EnteredBy = canditateinfos.EnteredBy;
canditateinfo.EnteredDate = canditateinfos.EnteredDate;
canditateinfo.DeleteFlag = canditateinfos.DeleteFlag;
canditateinfo.IsActive = canditateinfos.IsActive;
canditateinfo.CanditateId = canditateinfos.CanditateId;
canditateinfo.UpdatedBy = HttpContext.Session.GetString("username");
canditateinfo.UpdatedDate = DateTime.Now;
_context.Update(canditateinfo);
await _context.SaveChangesAsync();
TempData["SuccessMessage"] = "Canditate Updated Successfully";
return RedirectToAction(nameof(Index));
}
}
catch
{
}
}
return View(canditateinfo);
}
Nested ifs do not matter for the outer control flow. (Yours do, though but hear me out ;D )
In ...
if ( condition1 )
{
// body1
}
else if( condition2 )
{
// body2
}
else
{
// body3
}
// aftermath
... "body3" will be executed if and only if neither condition1 nor condition2 evaluate to true.
That is regardless of any further nested if statements in "body1" or "body2". (Given, there are no fancy gotos or returns or the like... - more on this further down)
That also means:
If condition1 is true, the flow is "body1", "aftermath" (Note that in this case, it doesn't even matter what condition2 evals to.)
If condition1 is false and condition2 is true, the flow is "body2", "aftermath"
If condition1 is false and condition2 is false, the flow is "body3", "aftermath"
Now, in your code, you do have returns inside the inner if statements. This of course does influence the control flow.
They will "bail out" early. That means ...
if (condition1)
{
if (condition1_1)
{
return retVal1; // If 1 && 1_1 => Rest of method is not executed
}
// if !condition1_1 we end up at "aftermath" for the the next instruction
// because condition1 was true!!
}
else if (condition2)
{
if (condition2_1)
{
return retVal2; // If 2 && 2_2 => Rest of the method is not executed
}
// if !condition2_1 we end up at "aftermath" for the the next instruction
// because condition2 was true!!
}
else
{
// body3
}
// aftermath
So, if you want "body3" to be executed in those cases where the nested ifs do not bail out, you need to restructure this logic.
As far as I can see, those are sanity tests. I think if you do something like this, it should work as expected:
if (condition1 && condition1_1)
{ // here, BOTH primary AND secondary condition MUST evaluate to true
// so that this branch is entered
return retVal1; // If 1 && 1_1 => Rest of method is not executed
}
else if (condition2 && condition2_1)
{
return retVal2; // If 2 && 2_2 => Rest of the method is not executed
}
else
{
// body3
}
which can be simplyfied to
if (condition1 && condition1_1)
{
return retVal1; // If 1 && 1_1 => Rest of method is not executed
}
if (condition2 && condition2_1)
{
return retVal2; // If 2 && 2_2 => Rest of the method is not executed
}
// what was before body3
Note that in if (condition1 && condition1_1) C#/.NET is so kind to evaluate condition1_1 only if condition1 evaluates to true. Otherwise the whole expression evaluates to false. Which is correct:
If condition1 is false already, then condition1 && condition1_1 can never be true regardless of what condition1_1 would evaluate to, so it can stop early.
So, it is safe to write something like if( x is not null && x.IsValid ).
Fun fact:
Your original code would probably work as expected without the elses:
if( condition1 )
{
if ( subcondition1 )
{
// condition && subcondition == true
return errorCase1;
}
}
// you can land here if one of condition1 or subcondition1 is false
// and therefore go on to execute :
if( condition2 )
{
if ( subcondition2 )
{
return errorCase2;
}
}
// happy path here, aka "body3"
Related
Let there be two boolean variables a and b, and each combination of the truth values of both causes a particular different procedure. Check this code:
if(a)
{
// Block A
if(b)
{
// statement 1
}
else
{
// statement 2
}
}
else {
// Block B
if(b)
{
// statement 3
}
else
{
// statement 4
}
}
Is there any way to make it to be not repetitive without making a separate function? (What I mean by repetitive is block A and block B have the same conditional but different statement)
Would the switch expression work for you?
(a, b) switch {
(true, true) => ...,
(true, false) => ...`,
(false, true) => ...,
(false, false) => ...,
};
You could avoid nesting ifs like so
if(a && b)
{
// statement 1
}
else if(a && !b)
{
// statement 2
}
else if(!a && b)
{
// statement 3
}
else
{
// statement 4
}
I'm not sure you would consider it more succint, but I at least find it more readable.
I have some code written in C# for which I need to add some conditions. From one of my methods, I'm calling another method "UpdateData()", which updates some data into the database. Now for this, I need to add some conditions.
There will be appsetting in the config file, which is a boolean value. If the value is true, then the conditions in point2 have to be checked, if the value is false, it has to directly call UpdateData() method.
There are few types and statuses which needs be checked if the point1 is true.
Condition 1: If type is 'A' and status is "Complete" - then call "UpdateData()".
Condition 2 : If type is 'B' and status is "Complete" or "Partial" or "some xyz" - then call "UpdateData()".
So for this I have written the below code :
bool checkStatus = Convert.ToBoolean(ConfigurationManager.AppSettings["CheckStatus"]);
if (checkStatus)
{
if (type == "A" && status == "Complete")
{
UpdateData();
}
else if (type == "B" && (status == "Complete" || status == "Other status" || status == "someother status"))
{
UpdateData(); // for type B , data should not be updated if status is anything other than those in condition.
}
}
else
{
UpdateData();
}
This is working as expected. But I do not want to write nested if-else. If tomorrow there is some other status and type I need to include, I need to add another if condition here.
Is there any better or optimized way of writing it?
I personally think what you have is fine. However, if you really don't like it, you could fiddle with local methods i guess
bool CheckA() => type == "A" && status == "Complete";
bool CheckB() => type == "B" && (status == "Complete" || status == "Other status" || status == "someother status")
if (!checkStatus || CheckA() || CheckB())
UpdateData();
or
bool Check(string val, params string[] list) => type == val && list.Contains(status);
// uglay, yet approachable
if (!checkStatus ||
Check("A", "Complete") ||
Check("B", "Complete", "Other status", "someother status"))
{
UpdateData();
}
Note : I personally wouldn't do these, though it might be your cup of tea
If it is to optimise the ability to add a new one quickly, I would've put it in an array.
bool[] checks = new bool[]{
(type == "A" && status == "Complete"),
(type == "B" && (status == "Complete" || status == "Other status" || status == "someother status"))
}
if (!checkStatus || checks.Contains(false)) //'Contains' requires Linq, it also works with 'checks.Any(c => !c)'
{
UpdateData();
}
This way you only need to add a new condition in the bool array and you don't have to update the if-statement for it. And you can comment out one quickly if you don't need it.
Though, it's usefulness depends on how many conditions you may expect to add.
I guess the main point of this code is to ensure the update runs when the conditions are met, which is done via unit testing.
So, I would look at how I could write this code in a testable manner so I can be sure that it does what it says on the tin.
One way to do it could be something like this:
public bool AppSettingsRunStatusMet(string appSettingsCheckStatus)
{
return Convert.ToBoolean(appSettingsCheckStatus);
}
public bool TypeARunStatusMet(string type, string status)
{
return (type.Equals("A") && status.Equals("Complete"))
}
public bool TypeBRunStatusMet(string type, string status)
{
return (
type.Equals("B") &&
(
status.Equals("Complete") ||
status.Equals("Other status") ||
status.Equals("someother status")
)
}
This is starting to shape up as a rules engine and you can have as many rules as you need
each if statement can now call one method and each rule is separated in its own method which can now be easily tested properly.
You could put all rules in their own class(es), have the engine return a status and if that status is true then run the update. The main idea is to separate config code, from the status analysis and from the code which runs the update and does whatever it is it needs to do.
I'd prefer doing something like this, so that when new cases shows up or validation criteria changes we can just whitelist new case. This is simple/maintainable, works well for growing set of valid_cases with little changes.
using System;
using System.Collections.Generic;
public class Program
{
class Case{
string type;
string status;
public Case(string type_val, string status_val ){
status = status_val;
type = type_val;
}
public override int GetHashCode()
{
return type.GetHashCode()+status.GetHashCode();
}
public override bool Equals(object obj)
{
Case test = obj as Case;
if (test== null)
return false;
return type == test.type && status == test.status ;
}
}
public static void Main()
{
bool checkStatus = true;
HashSet<Case> vaild_cases = new HashSet<Case>();
vaild_cases.Add(new Case("A","Complete"));
vaild_cases.Add(new Case("B","Complete"));
vaild_cases.Add(new Case("B","Other status"));
vaild_cases.Add(new Case("B","someother status"));
Case current_case = new Case("A","Complete");
if (!checkStatus || vaild_cases.Contains(current_case))
UpdateData();
}
static void UpdateData()
{
Console.WriteLine("Hello, World!");
return;
}
}
Cheers !!
Another option is this:
if((new string[] {"Complete", "Other status", "someother status"}.Contains(status) && type == "B") ||
(status == "Complete" && type == "A") ||
!checkStatus)
{
UpdateData();
}
There are three properties in the object
{obj.prop1, obj.prop2, obj.prop3} These properties are NULLABLE INTEGER
And I need to validate either all three properties should contain some value or all three properties are null.
Here's the validation
if (!((!obj.prop1.HasValue && !obj.prop2.HasValue && !obj.prop3.HasValue) ||
(obj.prop1.HasValue && obj.prop2.HasValue && obj.prop3.HasValue)))
{
//throw new Exception("");
}
Is there any better way to do it via some other Logical operators?
You can try this
if (obj.prop1.HasValue != obj.prop2.HasValue || obj.prop2.HasValue != obj.prop3.HasValue)
throw...
The expression above yields:
p1.HasValue p2.HasValue p3.HasValue
==========================================================================
false false false => false || false => false
false false true => false || true => true
false true false => true || true => true
true false false => true || false => true
false true true => true || false => true
true true false => false || true => true
true false true => true || true => true
true true true => false || false => false
You could use null coalescing for the null check, but you would still need to verify if all items do actually have a value for the other:
if((obj.prop1 ?? obj.prop2 ?? obj.prop3) == null
|| (obj.prop1.HasValue && obj.prop2.HasValue && obj.prop3.HasValue))
{
// conditional block
}
However, I think the original way you have it is more understandable to an average user.
I don't know of a logical operator that can make the code look nicer, but what I often do is wrap the functionality in to a method with a name that describes the test. This helps reduce the code size, and makes the code "self documenting".
Here's an example method that will test a bunch of objects to see if they are "partially null".
private static bool ArePartiallyNull(params object[] values)
{
if(values.Length <= 1)
return false;
var isNull = values[0] == null;
for(var i = 1;i < values.Length;i++)
{
if(isNull != (values[i] == null))
return true;
}
return false;
}
And this method in action: https://dotnetfiddle.net/6QIpDF
public class Program
{
public static void Main()
{
int? one = 1;
int? two = 1;
int? three = 1;
int? nullOne = null;
int? nullTwo = null;
int? nullThree = null;
Console.WriteLine(ArePartiallyNull(one, two, three));
Console.WriteLine(ArePartiallyNull(nullOne, nullTwo, nullThree));
Console.WriteLine(ArePartiallyNull(one, two, nullThree));
}
private static bool ArePartiallyNull(params object[] values)
{
if(values.Length <= 1)
return false;
var isNull = values[0] == null;
for(var i = 1;i < values.Length;i++)
{
if(isNull != (values[i] == null))
return true;
}
return false;
}
}
There are actually a handful of ways you can go about this depending on how "automatic" you want it to be when you add new properties for the object. If you don't mind updated your check each time you add a new property, I would just go with a simple method for comparison.
First, the example you have provided is a just fine approach. This is actually going to be the most performant way to perform the check. The downside is it is overly verbose, and doesn't scale well if you plan to add a lot more properties to the object.
The next method you could consider is to create a custom function that compares the properties for you. This way, when you use the function in your code, it is a bit less verbose. The function below will take as many int? variables you want to throw at it, and verify that they all either have a value, or don't have a value.
bool Test(params int?[] props)
{
bool? lastValue = null;
foreach(int? p in props)
{
// We haven't got a status yet so we just use the status for the first prop
if (lastValue.HasValue == false)
lastValue = p.HasValue;
else
{
// If the status of this next prop doesn't match the first, we know it is false
if (p.HasValue != lastValue.Value)
return false;
}
}
// Default back to true since we didn't identify any issues.
return true;
}
The last option I would propose would be to use reflection. With reflection, you could loop over the properties and check each one using similar logic to the function above. The benefit of this approach is that you do not need to adjust your logic as you add new properties. The downside is performance.
If you just want to make sure that all three have a value or don't have a value (regardless of what the value is) then
bool AllAreTrueOrFalse(params bool[] values)
{
return values.All(value=>value) || !values.Any(value=>value);
}
var allTrueOrFalse = AllAreTrueOrFalse(obj.prop1.HasValue, obj.prop2.HasValue,
obj.prop3.HasValue);
So I'm trying to use FindAll to return a list of objects that match. It works great when I only use one condition, for example
patientstatus = statuslist.FindAll(delegate(StatusReader.onestatus p1)
{
return p1.WL_ID == patlist[i].wl_id;
});
But I would like to use multiple conditions, some of which contain if statements and I can't figure out how. It seems like the format needs to have a return statement, and the example from Microsoft (http://msdn.microsoft.com/en-us/library/fh1w7y8z.aspx) only uses one condition.
I could either have multiple FindAll methods for each condition, or just make a loop that scans through all the values myself, but there's got to be an obvious thing I'm missing, right?
I'm not quite sure what "if loops" are, but you can always just stitch them together:
patientstatus = statuslist.FindAll(delegate(StatusReader.onestatus p1)
{
if(p1.WL_ID != patlist[i].wl_id)
return false;
if(otherStuff != 5)
return false;
for(var x in p1.stuff)
if(x == 7)
return false;
return true;
});
Try the following:
var patientStatus = statusList.Where(p => p
{
// Put in logic here as you need
return p.WL_ID == patlist[i].wl_id || p.YourSecondProperty == WhateverYouWantToCheck;
}
You can think about something like
public abstract class Condition
{
public abstract bool Sutisfied(StatusReader.onestatus status);
}
public class Condition1 : Condition
{
public override bool Sutisfied(StatusReader.onestatus status) {
//check for something and return
}
}
public class Condition2 : Condition
{
public override bool Sutisfied(StatusReader.onestatus status) {
//check for something and return
}
}
After can have a list of conditions, like
List<Condition> conditions =
new List<Condition>{new Conditon1(), new Condition2()}
and after this list use inside
patientstatus = statuslist.FindAll(delegate(StatusReader.onestatus status)
{
return conditions.TrueForAll(c=>c.Sutisfied(status));
});
Your delegate simply needs to return true for a match to your conditions and false for a non-match to your conditions. It doesn't have to be a single line return statement. You can create boolean values, have if statements, for loops, and anything else you want in your delegate - so long as it returns true or false along all code paths.
So you can do as many if statements or loops as you want.
If you really want to maintain it as one line, you can do something like the following...
return (condition1 == condition1) || (condition2 == condition2) || (condition3 == condition3);
I have several bool checks against values. I wanted to check in ANY of the values return false then do something.
I attempted the follow:
bool formIsValid = true;
try{
Utility.testStringHasValue(txEmail.Text); <--- true
Utility.testStringHasValue(txFirstName.Text); <--- true
Utility.testStringHasValue(txLastName.Text); <--- FALSE
Utility.testStringHasValue(txUserEmployer.Text); <--- true
Utility.testStringHasValue(txUserPassword.Text); <--- true
Utility.testStringHasValue(txUserPassword2.Text); <--- true
}
catch (Exception)
{
formIsValid = false
}
.. any other solutions as this one does not at all!
UPDATE
I removed the Try/Catch completely and used:
bool isFormValid = Utility.testStringHasValue(txEmail.Text)
&& Utility.testStringHasValue(txFirstName.Text)
&& Utility.testStringHasValue(txLastName.Text)
&& Utility.testStringHasValue(txUserEmployer.Text)
&& Utility.testStringHasValue(txUserPassword.Text)
&& Utility.testStringHasValue(txUserPassword2.Text)
&& (txUserPassword.Text == txUserPassword2.Text);
Dont use exceptions for that scenario, when an exception is thrown there is a performance hit.
There is also a method available already to check if a string is entered ( String.IsNullOrEmpty )
You could use the && (and) operator to validate all fields are valid.
eg:
bool isValid = !String.IsNullOrEmpty(txtEmail.Text) && !String.IsNullOrEmpty(txtFirstname.Text) && !String.IsNullOrEmpty(txtLastName.Text);
Alternatively, you could flip it the other way using the || (or) operator
bool isInvalid = String.IsNullOrEmpty(txtEmail.Text) || String.IsNullOrEmpty(txtFirstname.Text) || String.IsNullOrEmpty(txtLastName.Text);
If you wrote the Utility methods, then I would suggest making sure it won't throw an exception, especially if it returns a boolean indicating whether the string has a value.
You could just do the following, and avoid the try { } catch { } entirely.
bool formIsValid = Utility.testStringHasValue(txEmail.Text); <--- true
&& Utility.testStringHasValue(txFirstName.Text); <--- true
&& Utility.testStringHasValue(txLastName.Text); <--- FALSE
&& Utility.testStringHasValue(txUserEmployer.Text); <--- true
&& Utility.testStringHasValue(txUserPassword.Text); <--- true
&& Utility.testStringHasValue(txUserPassword2.Text); <--- true
&& will not call evaluate the right side unless the left side returns true, so Utility.testStringHasValue will only actually be called 3 times in your example.
if ( Utility.testStringHasValue(txEmail.Text) &&
Utility.testStringHasValue(txFirstName.Text) &&
Utility.testStringHasValue(txLastName.Text) &&
Utility.testStringHasValue(txUserEmployer.Text) &&
Utility.testStringHasValue(txUserPassword.Text) &&
Utility.testStringHasValue(txUserPassword2.Text)
) {
all_good = true;
} else {
no_so_good = true;
}
Exception handling should not be used as control logic. It obfuscates the purpose.
That's because returning false doesn't throw an exception. You could always do:
if (!(
Utility.testStringHasValue(txEmail.Text) &&
Utility.testStringHasValue(txFirstName.Text) &&
Utility.testStringHasValue(txLastName.Text) &&
Utility.testStringHasValue(txUserEmployer.Text) &&
Utility.testStringHasValue(txUserPassword.Text) &&
Utility.testStringHasValue(txUserPassword2.Text)))
{
throw new Exception("Something is false");
}
if ( !(condtion1 && condition2 && .... && conditionN) )
{
// first condition evaluating to false gets you here
// anything afterwards is not checked.
}
Recode your Utility.testStringHasValue() to return false, not throw an exception.
Next
formIsValid= Utility.testStringHasValue(txEmail.Text) &&
Utility.testStringHasValue(txFirstName.Text) &&
Utility.testStringHasValue(txLastName.Text) &&
Utility.testStringHasValue(txUserEmployer.Text) &&
Utility.testStringHasValue(txUserPassword.Text) &&
Utility.testStringHasValue(txUserPassword2.Text) ;
if (formIsValid) {
//whatever
} else {
//whatever
}
What does testStringHasValue return? if a boolean then just use all the combined return values instead, like this :
boolean result = true;
result = result && Utility.testStringHasValue(txEmail.Text);
result = result && Utility.testStringHasValue(txFirstName.Text);
return result;
The way you are using exceptions is not very good. They should not be used for this kind of validation and your intention to reach the catch will only be valid if you actuelly throw a exception not onyl because it returns a boolean false value.
try..catch exception handling is more expensive than a simple boolean check, resource-wise. From the msdn site re: try..catch: "Catching exceptions at runtime creates additional overhead, and is likely to be slower than pre-checking to avoid exceptions."
Use if..then as shown previously.
Have you thought about writing a reusable method to check all the values passed to it aren't empty? Something like this could be a major time saver if you are using the code in multiple places:
using System.Linq;
public static class Utility
{
public static bool EnsureValuesNotEmpty(params string[] values)
{
return values.All(value => !string.IsNullOrWhiteSpace(value));
}
}
Then you can re-use the functionality with a lot less code, just pass all the values you want to check to it:
var formIsValid = Utility.EnsureValuesNotEmpty(txEmail.Text,
txFirstName.Text,
txLastName.Text,
txUserEmployer.Text,
txUserPassword.Text,
txUserPassword2.Text);