Ternary condition in c# logic not working as desired - c#

I have written a ternary condition in c# which isnt evaluating correctly. I am checking if both condition satisfy then it should return true otherwise false. At the moment it is returning true even if one condition fails. So even if the docType is Flashnotes is true, the canView is setting to true. Consider this IoC.Resolve().Authorize("Put", "ManageDocuments")
always returning true and docType may or may not return true
doc.canView = IoC.Resolve<IClientAuthorizationService>().Authorize("Put", "ManageDocuments") ==
AuthAccessLevel.Full && i.DOCUMENT_TYPE_ID != (int) DocumentType.FlashNotes ||
i.DOCUMENT_TYPE_ID != (int)DocumentType.CallMeetingNotes ||
i.DOCUMENT_TYPE_ID != (int)DocumentType.OtherNotes ||
i.DOCUMENT_TYPE_ID != (int)DocumentType.TearSheet
? true
: false;

If I've understood this correctly one of the i.DOCUMENT_TYPE_ID consditions must equate to true? Add parenthesis to equate that first.
doc.canView = IoC.Resolve<IClientAuthorizationService>().Authorize("Put", "ManageDocuments") ==
AuthAccessLevel.Full && (i.DOCUMENT_TYPE_ID == (int) DocumentType.FlashNotes ||
i.DOCUMENT_TYPE_ID == (int)DocumentType.CallMeetingNotes ||
i.DOCUMENT_TYPE_ID == (int)DocumentType.OtherNotes ||
i.DOCUMENT_TYPE_ID == (int)DocumentType.TearSheet)
Also there's no need for the true or false as it's already a bool.

I think what you're trying to do can be simplified into something like this:
var rejectedTypes = new[] { DocumentType.FlashNotes, DocumentType.CallMeetingNotes,
DocumentType.OtherNotes, DocumentType.TearSheet }.Cast<int>();
var accessLevel = IoC.Resolve<IClientAuthorizationService>()
.Authorize("Put", "ManageDocuments");
doc.canView = ((accessLevel == AuthAccessLevel.Full) &&
!rejectedTypes.Contains(i.DOCUMENT_TYPE_ID));

I think there's a mistake in the logic here. Try:
doc.canView = IoC.Resolve<IClientAuthorizationService>().Authorize("Put", "ManageDocuments") ==
AuthAccessLevel.Full && !(i.DOCUMENT_TYPE_ID == (int) DocumentType.FlashNotes ||
i.DOCUMENT_TYPE_ID == (int)DocumentType.CallMeetingNotes ||
i.DOCUMENT_TYPE_ID == (int)DocumentType.OtherNotes ||
i.DOCUMENT_TYPE_ID == (int)DocumentType.TearSheet);

It's an order of operations problem. You can find out more about ordering it here:
doc.canView = IoC.Resolve<IClientAuthorizationService>().Authorize("Put", "ManageDocuments") ==
AuthAccessLevel.Full && (i.DOCUMENT_TYPE_ID != (int) DocumentType.FlashNotes &&
i.DOCUMENT_TYPE_ID != (int)DocumentType.CallMeetingNotes &&
i.DOCUMENT_TYPE_ID != (int)DocumentType.OtherNotes &&
i.DOCUMENT_TYPE_ID != (int)DocumentType.TearSheet)
? true // Redundant code but included to show ternary operator
: false;

Related

C# How to make this code easier and shorter

I am beginner and i wanna ask how to make this code more simple and shorter
Thanks for all replies
public static bool SelectedSingleAcc(SpecialForms.AccountManager am)
{
//checkbox1
if (am.selectedCB1.Checked == true
&& am.selectedCB2.Checked == false
&& am.selectedCB3.Checked == false
&& am.selectedCB4.Checked == false
&& am.selectedCB5.Checked == false
&& am.selectedCB6.Checked == false
&& am.selectedCB7.Checked == false
&& am.selectedCB8.Checked == false) return true;
//checkbox2
if (am.selectedCB1.Checked == false
&& am.selectedCB2.Checked == true
&& am.selectedCB3.Checked == false
&& am.selectedCB4.Checked == false
&& am.selectedCB5.Checked == false
&& am.selectedCB6.Checked == false
&& am.selectedCB7.Checked == false
&& am.selectedCB8.Checked == false) return true;
//checkbox3
if (am.selectedCB1.Checked == false
&& am.selectedCB2.Checked == false
&& am.selectedCB3.Checked == true
&& am.selectedCB4.Checked == false
&& am.selectedCB5.Checked == false
&& am.selectedCB6.Checked == false
&& am.selectedCB7.Checked == false
&& am.selectedCB8.Checked == false) return true;
//checkbox4
if (am.selectedCB1.Checked == false
&& am.selectedCB2.Checked == false
&& am.selectedCB3.Checked == false
&& am.selectedCB4.Checked == true
&& am.selectedCB5.Checked == false
&& am.selectedCB6.Checked == false
&& am.selectedCB7.Checked == false
&& am.selectedCB8.Checked == false) return true;
//checkbox5
if (am.selectedCB1.Checked == false
&& am.selectedCB2.Checked == false
&& am.selectedCB3.Checked == false
&& am.selectedCB4.Checked == false
&& am.selectedCB5.Checked == true
&& am.selectedCB6.Checked == false
&& am.selectedCB7.Checked == false
&& am.selectedCB8.Checked == false) return true;
//checkbox6
if (am.selectedCB1.Checked == false
&& am.selectedCB2.Checked == false
&& am.selectedCB3.Checked == false
&& am.selectedCB4.Checked == false
&& am.selectedCB5.Checked == false
&& am.selectedCB6.Checked == true
&& am.selectedCB7.Checked == false
&& am.selectedCB8.Checked == false) return true;
//checkbox7
if (am.selectedCB1.Checked == false
&& am.selectedCB2.Checked == false
&& am.selectedCB3.Checked == false
&& am.selectedCB4.Checked == false
&& am.selectedCB5.Checked == false
&& am.selectedCB6.Checked == false
&& am.selectedCB7.Checked == true
&& am.selectedCB8.Checked == false) return true;
//checkbox8
if (am.selectedCB1.Checked == false
&& am.selectedCB2.Checked == false
&& am.selectedCB3.Checked == false
&& am.selectedCB4.Checked == false
&& am.selectedCB5.Checked == false
&& am.selectedCB6.Checked == false
&& am.selectedCB7.Checked == false
&& am.selectedCB8.Checked == true) return true;
return false;
}
// get all values into an array for easier handling:
values = new[]
{
am.selectedCB1.Checked,
am.selectedCB2.Checked,
am.selectedCB3.Checked,
am.selectedCB4.Checked,
am.selectedCB5.Checked,
am.selectedCB6.Checked,
am.selectedCB7.Checked,
am.selectedCB8.Checked,
};
// find out if exactly one is true
return values.Count(val => val == true) == 1;
That said... the correct UI decision would be to use radio buttons instead of check boxes. They already implement this logic for you. And any time you catch yourself numbering your variables, you should think hard about why this should not be an array instead of many single variables.
public static bool SelectedSingleAcc(SpecialForms.AccountManager am)
{
int checkedNumbers = 0;
if (am.selectedCB1.Checked) checkedNumbers++;
if (am.selectedCB2.Checked) checkedNumbers++;
if (am.selectedCB3.Checked) checkedNumbers++;
if (am.selectedCB4.Checked) checkedNumbers++;
if (am.selectedCB5.Checked) checkedNumbers++;
if (am.selectedCB6.Checked) checkedNumbers++;
if (am.selectedCB7.Checked) checkedNumbers++;
if (am.selectedCB9.Checked) checkedNumbers++;
if (checkedNumbers == 1) //only one checkbox selected, we think the result is true
return true;
return false;
}
So it looks like you're checking that at most one checkbox is checked the n return true, otherwise return false
Because, in order to even appear on a form, controls have to be added to a Controls collection we can search through it (using LINQ) looking for controls that match a criteria. In this case we'll look through the controls for any that are checkboxes, and counting those whose name starts with "selectedCB" and whose state is checked. We compare the count to 1, and if there is only 1 then the result is true, if there are 0 or 2+ the result is false:
return p.Controls
.OfType<Checkbox>()
.Count(c => c.Name.StartsWith("selectedCB") && c.Checked) == 1;
p is the name of the panel/group box that holds the checkboxes.
If they are straight on the form use this (or the name of the form variable, if this code isn't part of the form that holds the boxes).
If there are no other checkboxes in the panel/on the form you can remove the c.Name.StartsWith.... The check on name is purely there to stop e.g. your isActiveCheckbox being checked and hence also polluting the count
If there are other checkboxes also having a name that starts with "selectedCB", it would be simplest to rename them so that only these 8 checkboxes have a name starting with "selectedCB", or put them in their own panel but add a comment if you want a more refined logic eg a Regex that insists the name be selectedCB[1-8]
It looks like the rule you're implementing is an exclusive OR condition between then status of the 8 checkboxes.
IN that case using C#'s XOR operator ^ would probably yield a contender for the shortest solution e.g.
public static bool SelectedSingleAcc(SpecialForms.AccountManager am)
{
return am.selectedCB1.Checked
^ am.selectedCB2.Checked
^ am.selectedCB3.Checked
^ am.selectedCB4.Checked
^ am.selectedCB5.Checked
^ am.selectedCB6.Checked
^ am.selectedCB7.Checked
^ am.selectedCB8.Checked;
}
With that said, I would advise against using the XOR ^ operator, and consider something similar to nvoigt's answer, on the grounds that it is seldom used meaning many developers wouldn't be familiar with it, thereby impeding the code's readability.

Get parent entity according to some property filter in child table

Id like to get all the parent that doesn't have in the signature table anything with
(Roleid 1 OR Roleid 2 OR Roleid 3) AND SignatureStatus IS <> NULL
RoleId - int: 0-13
SignatureStatus - bit: True, False, Null
I have this code but i still get the parent when i shouldn't and not getting it when i should..
result = Context.APP_AuthorityHasamaForm.Where(x =>
x.UpdateTypeId == (int)UpdateType.Unit && x.AuthorityNum == authorityUnit.AuthorityNum &&
x.InsertDate >= authorityUnit.FromDate && x.HasamaFormStatus == (int)Status.Valid &&
!(x.APP_SignatureAuthorityHasamaForm.Any(s =>
s.RoleId == (int)Role.EligibilityWorker1 || s.RoleId == (int)Role.DepartmentManager2 ||
s.RoleId == (int)Role.Treasurer3 && ((bool)s.SignatureStatus || !(bool)s.SignatureStatus)))).ToList();
How about changing it to be this?
!(x.APP_SignatureAuthorityHasamaForm.Any(s =>
(s.RoleId == (int)Role.EligibilityWorker1 || s.RoleId == (int)Role.DepartmentManager2 ||
s.RoleId == (int)Role.Treasurer3) && s.SignatureStatus.HasValue))).ToList();
I don't have your class structure but here goes few fixes , put brackets outside OR condition and use .HasValue for checking non null :
.Any(s =>
(s.RoleId == (int)Role.EligibilityWorker1 || s.RoleId == (int)Role.DepartmentManager2 ||
s.RoleId == (int)Role.Treasurer3) && ((bool)s.SignatureStatus.hasValue).ToList();

Multiple using of || and && operands

I have a query using Entity Framework. It has many different operands and I am confused with its priority. I am getting the wrong result. I need all records that IsPaid == true or IsPaid == null, also all records must be TypeId == 1 or TypeId == 2, also must be CityId == 1 and CategoryId == 2. For some reason it doesn't evaluate CityId and CategoryId.
What am I doing wrong? Thanks.
var list = db.Ads.Where (x =>
x.IsPaid == true || x.IsPaid == null &&
x.TypeId == 1 || x.TypeId == 2 &&
x.CityId == 1 && x.CategoryId == 2
).ToList();
The best way to solve this problem is using brackets.
You should always use them even if you know the binding prioritys, to increase readability of your code.
(x.IsPaid == true || x.IsPaid == null) && (x.TypeId == 1 || x.TypeId == 2) && x.CityId == 1 && x.CategoryId == 2
&& has a higher proirity than ||
So false && false || true would be translated to (false && false) || true => true
Sidenote as mentioned by #Joey:
Instead of (x.IsPaid == true || x.IsPaid == null) you can write (x.IsPaid != false).
Due to operator precedence, && binds higher than ||.
If you chain Where statements, it's more clear what happens:
var list = db.Ads
.Where(x => x.IsPaid == true || x.IsPaid == null)
.Where(x=> x.TypeId == 1 || x.TypeId == 2)
.Where(x=> x.CityId == 1)
.Where(x=> x.CategoryId == 2)
.ToList();
&& has a higher precedence than ||, just like in math. So, effectively your condition is the following:
x.IsPaid == true ||
x.IsPaid == null && x.TypeId == 1 ||
x.TypeId == 2 && x.CityId == 1 && x.CategoryId == 2
If any of those expressions on separate lines are true, the whole expression is true. You have to use parentheses to clarify here:
(x.IsPaid == true || x.IsPaid == null) &&
(x.TypeId == 1 || x.TypeId == 2) &&
x.CityId == 1 &&
x.CategoryId == 2
Try this:
var list = db.Ads.Where (
(x => x.IsPaid == true || x.IsPaid == null) &&
(x.TypeId == 1 || x.TypeId == 2) &&
(x.CityId == 1 && x.CategoryId == 2)
).ToList();

Not understanding LINQ query

I am maintaining a project and have come across some code which I can't understand. LINQ query:
var toDraw = from tile in testArr.AsEnumerable()
where tile.Item_Business_Unit != null ?
((tile.Ending_Date >= DateTime.Now || tile.Ending_Date == DateTime.MinValue) &&
((tile.Sales_Code == null) || (tile.Sales_Code.ToString() == customerNumber) ||
(tile.Sales_Code.ToString() == cpg)) && (tile.Unit_Price != 0)) :
((tile.Ending_Date >= DateTime.Now || tile.Ending_Date == DateTime.MinValue) &&
((tile.Sales_Code == null) || (tile.Sales_Code.ToString() == customerNumber) ||
(tile.Sales_Code.ToString() == cpg)) && (tile.Unit_Price != 0))
select tile;
From what I understand, from an array a tile is being selected which has the following criteria:
Ending date can be datetime.now or datetime.minvalue
Sales code can be null or can be equal to customer no or cpg
Unit price should be greater than 0
But I am not understanding why there is a conditional expression after tile.Item_Business_Unit since both of the conditions perform the same thing. So will the item be selected even if it has a null business unit? And does this work different from normal if/else operations?
Any suggestions would be very appreciated.
Are you being thrown by the shortcut notation?
x = (test_case) ? (true_part) : (false_part);
If test_case evaluates to true, you would have
Whereas if test_case evaluates to false, this expression would be evaluated
UPDATE:
As an FYI: The resulting test of both sides of that conditional expression above are equal, so that cryptic code is not even necessary.
You could replace that with this:
var toDraw = from tile in testArr.AsEnumerable()
where
((tile.Ending_Date >= DateTime.Now || tile.Ending_Date == DateTime.MinValue) &&
((tile.Sales_Code == null) || (tile.Sales_Code.ToString() == customerNumber) || (tile.Sales_Code.ToString() == cpg)) &&
(tile.Unit_Price != 0))
select tile;

EF Non-static method requires a target

I've serious problems with the following query.
context.CharacteristicMeasures
.FirstOrDefault(cm => cm.Charge == null &&
cm.Characteristic != null &&
cm.Characteristic.Id == c.Id &&
cm.Line != null &&
cm.Line.Id == newLine.Id &&
cm.ShiftIndex != null &&
cm.ShiftIndex.Id == actShiftIndex.Id &&
(newAreaItem == null ||
(cm.AreaItem != null &&
cm.AreaItem.Id == newAreaItem.Id)));
I get a TargetException: Non-static method requires a target when newAreaItem is null.
If newAreaItem is not null I get an NotSupportedException: Unable to create a constant value of type 'PQS.Model.AreaItem'. Only primitive types or enumeration types are supported in this context.
Things I've already checked if they're null:
c, newLine, actShiftIndex all 3 variables are not null and the Id is accessible.
I dont get it... please help.
If u need more information.. dont hesitate to ask...
UPDATE
I could eliminate the NotSupportedException, but I still got the TargetException when my newAreaItemIsNull is true.. :/
bool newAreaItemIsNull = (newAreaItem == null);
var mc = context.CharacteristicMeasures
.FirstOrDefault(cm => cm.Charge == null &&
cm.Characteristic != null &&
cm.Characteristic.Id == c.Id &&
cm.Line != null &&
cm.Line.Id == newLine.Id &&
cm.ShiftIndex != null &&
cm.ShiftIndex.Id == actShiftIndex.Id &&
(newAreaItemIsNull ||
(cm.AreaItem != null &&
cm.AreaItem.Id == newAreaItem.Id)));
UPDATE
I finally did it. It seems that the query parse can't parse my newAreaItem(IsNull) because it's not in the DB model somehow !?
I have to split my queries..
bool newAreaItemIsNull = (newAreaItem == null);
MeasureCharacteristic mc;
if (newAreaItemIsNull)
mc = context.CharacteristicMeasures
.FirstOrDefault(cm => cm.Charge == null &&
cm.Characteristic != null &&
cm.Characteristic.Id == c.Id &&
cm.Line != null &&
cm.Line.Id == newLine.Id &&
cm.ShiftIndex != null &&
cm.ShiftIndex.Id == actShiftIndex.Id);
else
mc = context.CharacteristicMeasures
.FirstOrDefault(cm => cm.Charge == null &&
cm.Characteristic != null &&
cm.Characteristic.Id == c.Id &&
cm.Line != null &&
cm.Line.Id == newLine.Id &&
cm.ShiftIndex != null &&
cm.ShiftIndex.Id == actShiftIndex.Id &&
cm.AreaItem != null &&
cm.AreaItem.Id == newAreaItem.Id);
Does someone know a better solution?
Try moving newAreaItem == null outside of the query
bool newAreaItemIsNull = (newAreaItem == null);
and replace newAreaItem == null with newAreaItemIsNull in query.
Query parser can only operate with the objects in the database, and newAreaItem is not one of them.
I had the exact same problem as you have when newAreaItem == null is true.
The problem comes from the fact that the item used in the LINQ cannot be null. Thus, when newAreaItem == null is true it means that newAreaItem is null and this leads to the error being thrown.
All you can do in my opinion is, after checking newAreaItem == null, to set the newAreaItem to a new empty object of that type if newAreaIteam is null. The newAreaItemIsNull condition will still be in place, thus the
(cm.AreaItem != null && cm.AreaItem.Id == newAreaItem.Id)
in your code below will still not be evaluated if newAreaItem is null.
context.CharacteristicMeasures.
FirstOrDefault(cm => cm.Charge == null &&
cm.Characteristic != null && cm.Characteristic.Id == c.Id &&
cm.Line != null && cm.Line.Id == newLine.Id &&
cm.ShiftIndex != null && cm.ShiftIndex.Id == actShiftIndex.Id &&
(newAreaItem == null ||
(cm.AreaItem != null && cm.AreaItem.Id == newAreaItem.Id)));

Categories

Resources