C# using LINQ and Nullable Boolean - c#

I have the below linq query which takes a text field which may be Y, N or DBnull and populates a boolean? parameter with either True, False or null depending on the value of the field.
var dset = from i in tbdc.Talkbacks
where i.talkback_id == id
select new Talkback(
i.talkback_id, i.acad_period, i.reference,
i.staff_member, i.date_received, i.no_talkers,
i.gender_id, i.names, i.type_id,
i.method_id, i.area_id, i.site_id,
i.category_id, i.date_closed, i.expenddate,
i.acknowledgementtarget,
(i.targetmet == "Y") ? true :
((i.targetmet == "N") ? false : null),
(i.acknowledgementtargetmet != "N") ? true : false
The problematic line is
(i.targetmet == "Y") ? true : ((i.targetmet == "N") ? false : null)
After reading up I found some documentation which states that the 2nd and 3rd arguments of the inline if need to be of the same type or be implicitly convertible to one another.
My question is, how do I get around this limitation to achieve my desired result?
I am relatively new to C# so am not familiar with all its quirks/capabilities yet.

My suggestion would be to replace it with :
(i.targetmet != null) ? (bool?)(i.targetmet == "Y") : null;
the reason why the compiler does not agree without the cast is that even if you store it into a nullable structure, the ternary operation checks if the results are compatible through an implicit conversion.
Results true and false are treated as bool literals, not bool?, thus not implicitly convertible to null. Casting either results to bool? will make them comparable. The one I suggested has an implicit convertion between bool? and null, and this works too:
(i.targetmet != null) ? (i.targetmet == "Y") : (bool?)null;
Which is an implicit conversion between a bool and bool?. I arbitrary prefer the first one..

You can explicitly convert one or more of the expressions to a bool?:
(i.targetmet == "Y") ? true : ((i.targetmet == "N") ? (bool?)false : (bool?)null)

Related

How to conditionally add something to an array?

Hello i am trying to use if statement when adding values to an array.
object[] array = new object[10]
{
defect.RecordStation,
defect.RecordUser,
repairTypeDict[defect.Id],
defect.Concern,
defect.Comments,
defect.RespCell,
null,
locationpartDict[defect.Id],
if( repairStandardTimeDict[defect.Id] == null)
repairActualTimeDict[defect.Id];
else
repairStandardTimeDict[defect.Id];
,
defect.Id,
};
i want to use the statement as 1 object
if( repairStandardTimeDict[defect.Id] == null)
repairActualTimeDict[defect.Id];
else
repairStandardTimeDict[defect.Id];
Thank you for help
The following expression
if( repairStandardTimeDict[defect.Id] == null)
repairActualTimeDict[defect.Id];
else
repairStandardTimeDict[defect.Id];
can be transformed to a single statement by using the ?: conditional operator
repairStandardTimeDict[defect.Id] == null
? repairActualTimeDict[defect.Id];
: repairStandardTimeDict[defect.Id];
or
repairStandardTimeDict[defect.Id] != null
? repairStandardTimeDict[defect.Id]
: repairActualTimeDict[defect.Id];;
The latter can be further simplified by ?? null-coalescing operator
repairStandardTimeDict[defect.Id] ?? repairActualTimeDict[defect.Id]
Here if the left hand side is not null then take that value otherwise take the right hand side.
You can use the null coleascing operator which would be object ?? valueIfObjectNull.
What this means is if the object on the left of the operator is null, it will default to the value on the right of the operator.

return statement that checks the first two characters before proceeding

return ship.DefenseType?.PropulsionMethod != null
? new BattleMethod(ship.DefenseType.PropulsionMethod)
: null;
Hi, my current return statement, above, is returning a Propulsion method if it's not null. However, my database has different types of
propulsion methods denoted by the first 2 letters in the field(PK, PA, PT, etc).
How can I check to make sure that the PropulsionMethod starts with "PK" before going further into the return statement?
In pseudo code, it might look something like this:
if (ship.DefenseType?.PropulsionMethod).startsWith("PK")
&& ship.DefenseType?.PropulsionMethod != null)
{
return new BattleMethod(ship.DefenseType.PropulsionMethod)
}
else
{
return null;
}
I tried
return ship.DefenseType?.PropulsionMethod != null &&
ship.DefenseType?.PropulsionMethod.StartsWith("PK")
? new BattleMethod(ship.DefenseType.PropulsionMethod)
: null;
But I get this error:
operator && cannot be applied to operands of type bool and bool?
Just add this condition too:
return ship.DefenseType?.PropulsionMethod != null
&& ship.DefenseType?.PropulsionMethod.StartsWith("PK")
? new BattleMethod(ship.DefenseType.PropulsionMethod) : null;
As the operator is && so the second condition will be evaluated if the first one was true (not null in this case).
You can compare nullable bool directly with true:
return ship.DefenseType?.PropulsionMethod?.StartsWith("PK") == true
? new BattleMethod(ship.DefenseType.PropulsionMethod)
: null;

Multiple inline comparison while assigning values to object properties

I am working on c# data model class, I created instance and assigning values from another object. I am aware of single line comparision but I need multiple, I have tried && operator but compiler complain 'invalid opperator'. I am sure what I am missing, surly it must be simple!
var answerDataModel = new AnswerDataModel()
{
Id = answerId,
//need help to
Value = AnswerDtoObject.Answers.FirstOrDefault() == null? &&
isSubQuestionExist == true ? "_SBQA"
: AnswerDtoObject.Answers.FirstOrDefault(),
};
if I remove "&& isSubQuestionExist == true ?", then code works
You have an errant ? operator. Just combine your comparisons in a single conditional operator:
Value = (AnswerDtoObject.Answers.FirstOrDefault() == null && isSubQuestionExist == true) ?
"_SBQA" :
AnswerDtoObject.Answers.FirstOrDefault()
Value = (AnswerDtoObject.Answers.FirstOrDefault() == null) &&
(isSubQuestionExist == true) ? "_SBQA"
: AnswerDtoObject.Answers.FirstOrDefault(),

C# ternary operator List operator

Any knows a quickest Ternary operation for this.
label1.Text = Cclass.TestMe()
.Where(t => t.GFName == (textBox1.Text == ""
? "GName"
: textBox1.Text))
.First()
.GFName == null ?
"Nothing" :
"Super";
I was trying to check if the List is empty return something. So the compiler will not throw a Exception or unhanded error.
The reason of this exception is First(). It will throw an exception if there's no row to be returned. Instead of that you can use FirstOrDefault() which will return the default value (NULL for all reference types) instead. But if you want to check if there any element inside your list which mathcing the condition, then you must use Any() extension method:
return Cclass.TestMe()
.Any(t => t.GFName == (textBox1.Text == "" ? "GName" : textBox1.Text)) ?
"Super" :
"Nothing";
By the way, it would be better to set text outside of your query:
var filteredText = textBox1.Text == "" ? "GName" : textBox1.Text;
return Cclass.TestMe().Any(t => t.GFName == filteredText) ?
"Super" :
"Nothing";
If I understand you right you want to return one value if the where clause returns something and another if not. That would be:
label1.Text = Cclass.TestMe()
.Any(t => t.GFName == (textBox1.Text == ""
? "GName"
: textBox1.Text)) ?
"Super" :
"Nothing";
If that's not what you want, then rearrange your code to use if statements to make it work, then make it better. Ugly working code is always better than elegant broken code.

Entity Framework 4 and Linq: OrderBy a field nested in a Query : refactor my code

First, Thomas Levesque had a good solution for ordering fields in a related table where the relation may not always be there:
userQuery = userQuery.OrderBy(u =>
(u.Department != null) ? u.Department.Name : String.Empty);
I need to do the same thing. My aggregate root is enormous:
myQuery = myQuery.OrderBy(p =>
(p.Seconds == null
? 0
: p.Seconds.FirstOrDefault() == null
? 0
: p.Seconds.First().Thirds == null
? 0
: p.Seconds.First().Thirds.FirstOrDefault() == null
? 0
: p.Seconds.First().Thirds.First().Forths == null
? 0
: p.Seconds.First().Thirds.First().Forths.FirstOrDefault() == null
? 0
: p.Seconds.First().Thirds.First().Forths.First().myField));
Is this really the way to do this, or is there something much easier to read? My other problem is that the nested myField has a matching "default" value sitting in the top level Query, also named by myField. The idea was to Order by the coalesce of these two fields (??).
Edit: I think this would include the "default value" from the first field:
myQuery = myQuery.OrderBy(p =>
(p.Seconds == null
? p.myDefaultField // Used to be zero
: p.Seconds.FirstOrDefault() == null
? p.myDefaultField
: p.Seconds.First().Thirds == null
? p.myDefaultField
: p.Seconds.First().Thirds.FirstOrDefault() == null
? p.myDefaultField
: p.Seconds.First().Thirds.First().Forths == null
? p.myDefaultField
: p.Seconds.First().Thirds.First().Forths.FirstOrDefault() == null
? p.myDefaultField
: p.Seconds.First().Thirds.First().Forths.First().myField));
How could I rewrite this OrderBy to be cleaner? This code fails with an error of "Cannot compare elements of type 'System.Collections.Generic.IEnumerable`1'. Only primitive types (such as Int32, String, and Guid) and entity types are supported."
I think you have a pretty nasty code smell going on here, but working with what you have got I wouldn't handle this in a LINQ query like that. Just for the sake of readability I'd do something like
myQuery = myQuery.OrderBy(p =>
(p.HasValidFields()
? p.Seconds.First().Thirds.First().Forths.First().myField
: p.myDefaultField
));
And inside of p's class
private bool HasValidFields
{
get
{
return p.Seconds != null &&
p.Seconds.FirstOrDefault() != null &&
.... ;
}
}

Categories