As I understand and read you can use short circuiting in if statement (&& or ||) in order for second condition not to fire. and if you want both condition to fire you would use single operands (& or |).
So say if I have inline if statement as below :
var test = (MyObject != null || string.IsNullOrEmpty(MyObject.Property)) ? string.Empty : MyObject.Property;
This will throw object reference error if MyObject is null, which in my opinion should not as I am using short circuiting. Can someone please explain this.
You're using the wrong condition. This part:
MyObject != null || string.IsNullOrEmpty(MyObject.Property)
should be:
MyObject == null || string.IsNullOrEmpty(MyObject.Property)
The RHS of an || only executes if the left hand is false. You want it to only execute if MyObject is not null.
EDIT: If you really want the MyObject != null part, you could change the whole thing to:
var test = MyObject != null && !string.IsNullOrEmpty(MyObject.Property)
? MyObject.Property : "";
Note the reversal of the 2nd and 3rd operands of the conditional operator too though.
You should have an == not an !=
var test = (MyObject == null || string.IsNullOrEmpty(MyObject.Property) ? string.Empty : MyObject.Property
Try this:
var test = (MyObject == null || string.IsNullOrEmpty(MyObject.Property)
? string.Empty : MyObject.Property
MyObject != null || string.IsNullOrEmpty(MyObject.Property)
Here you say.
If my object is not null.
or
string.IsNullOrEmpty(MyObject.Property)
Which means that if MyObject is null he will try to execute the second part.
MyObject == null || string.IsNullOrEmpty(MyObject.Property)
This won't throw null exception
That happens because MyObject is null and therefore the first condition is false so the second part must be evaluated to know the whole of the condition. Change the line to this:
MyObject != null && string.IsNullOrEmpty(MyObject.Property)
You should prefer readability instead of line-count, e.g.:
string prop = string.Empty;
if(MyObject != null && MyObject.Property != null)
prop = MyObject.Property;
(the reason for your exception was already explained in other answers)
Related
I have the following LINQ query:
houses.Where(x =>
x.A && user.B
||
(x.Address == null || user.Address == null ? false : x.Address.CountryCode == user.Address.CountryCode
))
I get an error when user.Address is null in:
user.Address.CountryCode
To avoid that I tried to use:
x.Address == null || user.Address == null
But it seems user.Address.CountryCode is still evaluated.
How can I avoid that?
It's definitely EF Core 3.0 query translator defect.
For now (and in general) you can avoid it by not using conditional operator ?: for criteria expressions which need to be converted to SQL query parameters (like your user.Address.CountryCode), but the equivalent logical binary expressions.
e.g. instead of
(x.Address == null || user.Address == null ? false : x.Address.CountryCode == user.Address.CountryCode)
use the equivalent
(x.Address != null && user.Address != null && x.Address.CountryCode == user.Address.CountryCode)
Personally I find this logic confusing. You might try:
( (x?.Address?.CountryCode != null && user?.Address?.CountryCode != null) ? x.Address.CountryCode == user.Address.CountryCode : false
If that doesn't work then there is something very odd going on with the Address or CountryCode properties! Probably and entity framework issue.
I'm having an issue where I want to return results where something matches and I get an error if one of the properties I'm trying to match is null.
if (!string.IsNullOrEmpty(searchString))
{
Infos = Infos.Where(
x =>
x.FirstName.ToLower().Contains(searchString) ||
x.LastName.ToLower().Contains(searchString) ||
x.ContractNum.ToLower().Contains(searchString) ||
x.VIN.ToLower().Contains(searchString) ||
x.Claim.InitiatedBy.ToLower().Contains(searchString)
).ToList();
}
If ContractNum or VIN, for example, are null then it throws an error. I'm not sure how to check if one of these are null inside of a linq query.
You can add explicit null checks:
Infos = Infos.Where(
x =>
(x.FirstName != null && x.FirstName.ToLower().Contains(searchString)) ||
(x.LastName != null && x.LastName.ToLower().Contains(searchString)) ||
(x.ContractNum != null && x.ContractNum.ToLower().Contains(searchString)) ||
(x.VIN != null && x.VIN.ToLower().Contains(searchString)) ||
(x.Claim != null && x.Claim.InitiatedBy != null && x.Claim.InitiatedBy.ToLower().Contains(searchString))
).ToList();
You have multiple options, first is to do an explicit check against null and the other option is to use Null propagation operator.
x.FirstName != null && x.FirstName.ToLower().Contains(searchString)
or
x.FirstName?.ToLower()?.Contains(searchString) == true
But I would suggest you to use IndexOf instead of Contains for case
insensitive comparison.
something like:
x.FirstName?.IndexOf(searchString, StringComparison.CurrentCultureIgnoreCase) >= 0)
Checking the property is null or empty before comparing it it's the only way I know
if (!string.IsNullOrEmpty(searchString))
{
Infos = Infos.Where(
x =>
(!String.IsNullOrEmpty(x.FirstName) && x.FirstName.ToLowerInvariant().Contains(searchString)) ||
(!String.IsNullOrEmpty(x.LastName) && x.LastName.ToLowerInvariant().Contains(searchString)) ||
(!String.IsNullOrEmpty(x.ContractNum) && x.ContractNum.ToLowerInvariant().Contains(searchString)) ||
(!String.IsNullOrEmpty(x.VIN) && x.VIN.ToLowerInvariant().Contains(searchString)) ||
(x.Claim != null && !String.IsNullOrEmpty(x.Claim.InitiatedBy) && x.Claim.InitiatedBy.ToLowerInvariant().Contains(searchString))
).ToList();
}
EXTRA: I added a check on the Claim property to make sure it's not null when looking at InitiatedBy
EXTRA 2: Using the build in function IsNullOrEmpty to compare string to "" and nullso the code is clearer.
Extra 3: Used of ToLowerInvariant (https://msdn.microsoft.com/en-us/library/system.string.tolowerinvariant(v=vs.110).aspx) so the lowering action will act the same no matter of the culture.
You could use ?? to replace it with a acceptable value.
(x.ContractNum??"").ToLower()
I would use the null conditional operator ?, this will however, return a nullable bool? so you will need to handle that appropriately.
Some examples on how to do this:
x?.FirstName?.ToLower().Contains(searchString) == true;
x?.FirstName?.ToLower().Contains(searchString) ?? false;
An alternative method to keep the comparison logic in one place to use a sub collection of the properties and check on those:
Infos = Infos.Where(i=>
new[] {i.FirstName,i.LastName,i.ContractNum /*etc*/}
.Any(w=> w?.ToLower().Contains(searchString) ?? false))
.ToList();
(It does read out all properties, but that shouldn't cost much performance and gains much maintainability )
This is my code..
object o = DBExecuteScalar(myQuery);
if ((int.parse(o.ToString())) <= 2 || (o is null))
{
// my task....
}
In this code, 'o is null' part is giving error. Any help how to deal with these both conditions in single if statement.. What I want is that the value of o should be (null,0,1,2).
Any help ??
In C#, the is operator checks for type equality. You need to check for null as o == null:
object o = DBExecuteScalar(myQuery);
if ((o == null) || (int.parse(o.ToString())) <= 2)
{
// my task....
}
You also need to check for null before you try to perform any actions on it
when you reverse the conditions in the if, then it should work.
In your case the ToString is called first on object o. But because o is null this will result in an exception.
When you reverse the order of your conditions, then the nullcheck will be first. The second part of the or (||) is only evaluated when the first part is false. This will prevent the exception from occurring
With || operator first condition is evaluated first - you want to check if is null first.
Also the int.Parse is not necessary. As RGraham mentioned is null is not a proper way how to check for null.
if (o == null || o == DBNull.Value || (int)o <= 2)
Here is an example of an assignment to a linq path pulled from code first...
applicants = appRegistrations
.ToList()
.Select(c => new ApplicantList() {
PartnerType = c.Participant != null ? c.Participant.PartnerType != null ? c.Participant.PartnerType.PartnerTypeName : "" : ""
});
Notice the null checks - is there a more elegant way I can write this code considering Participant AND PartnerType could be null?
I just hate checking for nulls on each property.
You could check if one of both are null:
List<ApplicantList> applicants = appRegistrations
.Select(ar => c.Participant == null || c.Participant.PartnerType == null
? "" : c.Participant.PartnerType.PartnerTypeName)
.Select(str => new ApplicantList { PartnerType = str })
.ToList();
You can shorten it a little bit:
PartnerType = c.Participant != null && c.Participant.PartnerType != null
? c.Participant.PartnerType.PartnerTypeName
: ""
When you construct the objects such as Participant, make sure that the properties are never null. Think if null is a valid value for a Participant? If not then you should never allow it to be null. Take a constructor parameter and add a guard clause to check for nulls. Otherwise initialize them to a default value.
Also, see NULL Reference Pattern.
Here is the query
from a in this._addresses
where a.Street.Contains(street) || a.StreetAdditional.Contains(streetAdditional)
select a).ToList<Address>()
if both properties in the where clause have values this works fine, but if for example, a.StreetAdditional is null (Most of the times), I will get a null reference exception.
Is there a work around this?
I'd use the null-coalescing operator...
(from a in this._addresses
where (a.Street ?? "").Contains(street) || (a.StreetAdditional ?? "").Contains(streetAdditional)
select a).ToList<Address>()
The most obvious one:
from a in this._addresses
where (a.Street != null && a.Street.Contains(street)) || (a.StreetAdditional != null && a.StreetAdditional.Contains(streetAdditional))
select a).ToList<Address>()
Alternatively you could write an extension method for Contains that accepts a null argument without error. Some might say that it is not so pretty to have such a method, because it looks like a normal method call, but is allowed for null values (thereby setting aside normal null-checking practices).
You must check first if StreetAdditional is null.
Try
where a.Street.Contains(street) || ((a != null) && a.StreetAdditional.Contains(streetAdditional))
This works because && is a shortcut-operator and if a != null yields false, the second expression with the null-value won't be evaluated since the result will be false anyway.
I would create an extension method to return an empty sequence if null and then call contains method.
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> pSeq)
{
return pSeq ?? Enumerable.Empty<T>();
}
from a in this._addresses
where a.Street.Contains(street) ||
a.StreetAdditional.EmptyIfNull().Contains(streetAdditional)
select a).ToList<Address>()
I don't think SqlServer gave you a null exception. If it did, then this code is clearly not running though LinqToSql (as you've tagged the question).
string.Contains would be translated to sql's like, which has no trouble at all with null values.
Check to make sure that the properties are not null
from a in this._addresses
where (a.Street != null && a.Street.Contains(street)) ||
(a.StreetAdditional != null && a.StreetAdditional.Contains(streetAdditional))
select a).ToList<Address>()
If the null check is false, then the second clause after the && will not evaluate.
from a in this._addresses
where a.Street.Contains(street) || (a.StreetAdditional != null && a.StreetAdditional.Contains(streetAdditional)
select a).ToList<Address>()
You might want to check to make sure the variables street and streetAdditional are not null. I just ran across the same problem and setting them to an empty string seemed to solve my problem.
street = street ?? "";
streetAdditional = streetAdditional ?? "";
from a in this._addresses
where a.Street.Contains(street) || a.StreetAdditional.Contains(streetAdditional)
select a).ToList<Address>()
One thing to note is that the null should be evaluated first.
where (**a.Street != null** && a.Street.Contains(street)) || (a.StreetAdditional != null && a.StreetAdditional.Contains(streetAdditional))
select a).ToList<Address>
()