简体   繁体   中英

C# for comparing two lists that may contain null values

I am comparing two excel sheets using C#.

I have assigned the sheets to datatables and I hope to compare the values in each cell. I have converted the datatables to lists and I'm iterating through them comparing them. How do I avoid a NullReferenceException if one of the values contains a null?

I am hitting a NullReferenceException at this point in the code:

    if (lst1[i].ToString() != lst2[j].ToString())

Is there a way to guard against nulls here or do I need to handle null values earlier in the code?

Thanks

One good way to do this is to ask if the value is null before call .ToString() .

So, would be like:

if (lst1[i] != null && lst2[j] != null && lst1[i].ToString() != lst2[j].ToString())

if (lst1[i]?.ToString() != lst2[j]?.ToString())

More info on the ?. operator

Just test for null before dereferencing lst1[i] and lst2[j]

if(lst1[i] is not null and lst2[j] is not null)
{
     if (lst1[i].ToString() != lst2[j].ToString())
     {
         ...
     }

}

Assuming

  • if both items are null then they are equal;
  • if both items are not null and their string representation are equal then they are equal;
  • in any other case they are not equal;

you can make comparison of your lists more readable With following LINQ query.

var query = list1
    .Zip(list2, (a, b) => new { a, b })
    .Any(m => !((m.a == null && m.b == null) || (m.a != null && m.b != null && m.a.ToString() == m.b.ToString())));

if (query)
{
    Console.WriteLine("Lists are not equal.");
}
else
{
    Console.WriteLine("Lists are equal.");
}

Since you're doing ToString() it looks like both lists are typed as objects. Since they're coming from Excel they're presumably all either strings or simple value types.

In that case you can do

if(lst1.SequenceEquals(lst2))

That compares each item in both lists and ensure that they're equal. It accounts for nulls. You wouldn't need to compare each item one at a time. This compares the entire list. I'd write unit tests to make sure it doesn't throw any curves.

If for some reason you wanted to do a text-based comparison ("2" == 2) then you could create a comparer like this:

public class ObjectTextComparer : IEqualityComparer<object>
{
    public bool Equals(object x, object y)
    {
        return x?.ToString() == y?.ToString();
    }

    public int GetHashCode(object obj)
    {
        return obj?.GetHashCode() ?? 0;
    }
}

and then this would return true:

var x = new object[] { "x", 2, null, "y" };
var y = new object[] { "x", "2", null, "y" };
var comparer = new ObjectTextComparer();
var listsAreEqual = x.SequenceEqual(y, comparer);

That second option is a can of worms, though, if the values in one list are stored in Excel as text and the other ones as numbers or dates.

For example if one list contains a date and the other list contains the same date stored as text, the comparer is going to convert the first one to a string, but it might not be formatted the same way as the other one stored as text, and the two strings won't match.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM