So I'm in a sticky situation where I have a collection of items of a certain model. For simplicity sake I've made a small model named CarModel
. In the collection it will have x amount of CarModel
where some of the objects have properties where the value is null.
As for right now, it will run the where
LINQ statement just fine on the first 3 items because they are null because it can check whether null == null
.. However, it can't check whether "Test" == null
, hence why I'm currently getting the exception
System.ArgumentNullException: 'Value cannot be null. Parameter name: value'
on this line cars.Where(x => x.Name?.ToLower().Contains(car.Name?.ToLower()) == true).ToList();
I was thinking about making the Name
property nullable to test if that would work but I'm tied to .NET Framework 4.0
and I'm not allowed to change it so I can't use nullable properties because that required C# 8.0 and the language version is tied to the framework so I'm on C# 7.3
using System.Collections.Generic;
using System.Linq;
using System;
class Program
{
static void Main(string[] args)
{
var car = new CarModel();
car.Name = null;
var cars = new List<CarModel>();
for (int i = 0; i < 3; i )
{
cars.Add(new CarModel { Name = null });
}
for (int i = 0; i < 3; i )
{
cars.Add(new CarModel { Name = "Test" });
}
var t = cars.Where(x => x.Name?.ToLower().Contains(car.Name?.ToLower()) == true).ToList();
}
}
internal class CarModel
{
public string Name { get; set; }
public int Year { get; set; }
}
How do I properly filter if some properties might be null at times. The goal right there is to return a collection of 3 items that it found because it matches the conditions in the WHERE statement.
CodePudding user response:
In the provided example car.Name
is always null
, but I assume that you've got an actual use case where that's not always true.
The exception you're getting is from the Contains
method, which can't handle a null
parameter. You'll need to add a check for that, either skipping the entire section (not shown) that deals with the matching list or initialize an empty list when car.Name
is null. Something like:
var t = car.Name is null ? new List<CarModel>() :
cars.Where
(
x => x.Name?.Contains(car.Name, StringComparison.InvariantCultureIgnoreCase) == true
).ToList();
That's assuming that you don't want to match null
with null
(as Yong Shun's answer does).
To be honest though, it might make more sense to ensure that your CarModel
object doesn't accept null
name values. Required a name in the constructor, use a property setter that throws on null
and so on. Depending on use case, of course.
CodePudding user response:
Just filter out the nulls before using the contains, you can't do a contains on a null value.
var t = cars.Where(x => x.Name != null && x.Name.ToLower().Contains(car.Name)).ToList();
CodePudding user response:
Perhaps you can write the query with dealing with 2 conditions:
- When the input value is
null
, queryName
withnull
. - When the input value is not
null
, queryName
with notnull
and perform a case-insensitive search. - Conditions 1 & 2 with
or
(fulfill either one).
var t = cars.Where(x => (car.Name == null && x.Name == null)
|| (car.Name != null && x.Name != null && x.Name.ToLower().Contains(car.Name.ToLower()) == true))
.ToList();
CodePudding user response:
The reason you get the exception error is because Contains method requires non-null argument.
so you should revise your code like below,
var t = cars.Where(x => x.Name?.ToLower().Contains(car.Name?.ToLower() ?? string.Empty) == true).ToList();