Home > Blockchain >  How do I properly deal with null values and 'where' using LINQ
How do I properly deal with null values and 'where' using LINQ

Time:03-04

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:

  1. When the input value is null, query Name with null.
  2. When the input value is not null, query Name with not null and perform a case-insensitive search.
  3. 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();

Sample program

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();
  • Related