简体   繁体   中英

Passed check on if not null is still assigning as null

I have created a matching method which basically takes in a Person object, makes a call to an address service and then tries to do a match firstly by trying like for like and then if that does not work it concatenates the house name/number with the saon information (flat 1a etc) to see if that works.

If it does find a match I need to store that matched address in my variable matchingAddress and then process that further which is what the rest of the method does, I have excluded this for clarity.

Problem

I think I have a problem with my lamda statement, on the second IF with the person I am debugging with the if statement is returning true and I am dropping into the assignment code however it is being set to null even though the IF statement is meant to be checking that it is not null .

Can anyone explain what is going on here?

private void AttemptMatch(Person person, string username)
        {
            var postcode = person.Postcode;

            List<JsonAddressModel> Addresses = _service.GetAddress(postcode); //returns a list of addresses for that persons postcode
            JsonAddressModel matchingAddress = new JsonAddressModel();

            //1.) Access the Service and see if theres a straight forward match
            if (Addresses.FirstOrDefault(x => x.paon.Trim() == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo) != null)
            {
                matchingAddress = Addresses.First(x => x.paon.Trim() == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo);                
            }

            //2.) try and combine the paon and saon and see if that matches address line one            

            if (Addresses.Where(x => String.Format("{0} {1}", x.paon.Trim(), x.saon.Trim()) == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo) != null)
            {
                matchingAddress = Addresses.Where(x => String.Format("{0} {1}", x.paon.Trim(), x.saon.Trim()) == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo).FirstOrDefault();
            }

            if (matchingAddress != null)
            {
                //rest of method to complete matching process for matched person         
            }

            else
                return;
        }

Stop repeating work you've already done 1 , and just remove some of this conditional logic:

//1.) Access the Service and see if theres a straight forward match
//if (Addresses.FirstOrDefault(x => x.paon.Trim() == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo) != null)
//{
matchingAddress = Addresses.FirstOrDefault(x => x.paon.Trim() == person.AddressLineOne &&
                x.thorofare.Trim() == person.AddressLineTwo) ??                
//}

//2.) try and combine the paon and saon and see if that matches address line one            

//if (Addresses.Where(x => String.Format("{0} {1}", x.paon.Trim(), x.saon.Trim()) == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo) != null)
//{
   /*matchingAddress = */
 Addresses.Where(x => String.Format("{0} {1}", x.paon.Trim(), x.saon.Trim()) ==
              person.AddressLineOne &&
              x.thorofare.Trim() == person.AddressLineTwo).FirstOrDefault();              
//}

Your current problem is caused because in the second if , you're not calling any selection method (like FirstOrDefault or ToList , etc) and so what you're checking is whether the query is null rather than any result.


1 At the moment, you run a query merely to determine whether it returns any results, and then you run the query again to actually obtain those results. Then, you potentially (if you'd not got the second if slightly wrong) do that same trick a second time, and use that to overwrite the previous result to boot, which was the actual result you wanted, I believe. So, instead, we just run one query, and if it returns null, we use ?? to move along and try the second query.

The reason you enter the if is that you are not calling FirstOrDefault() inside the condition. What's compared to null is the return of the Where method, which is never null .

You can optimize your code by storing the result of FirstOrDefault in a temporary variable, and then assigning it only when it's not null :

var tmp1 = Addresses.FirstOrDefault(x => x.paon.Trim() == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo);
if (tmp1 != null) {
    matchingAddress = tmp1;                
}
var tmp2 = Addresses.FirstOrDefault(x => String.Format("{0} {1}", x.paon.Trim(), x.saon.Trim()) == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo);
if (tmp2 != null) {
    matchingAddress = tmp2;
}

Try changing this:

Addresses.Where(x => String.Format("{0} {1}", x.paon.Trim(), x.saon.Trim()) == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo) != null

For

Addresses.Any(x => String.Format("{0} {1}", x.paon.Trim(), x.saon.Trim()) == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo) != null

And ideally you won't need that if. Your SingleOrDefault should be doing the trick.

Basically the Where never returns null, it just return an empty IEnumerable

never returns null value. You need to check if returned collection is empty.

I suppose the best option is to change "where" with "any"

if (Addresses.Any(x => String.Format("{0} {1}", x.paon.Trim(), x.saon.Trim()) == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo))

This linq is returning collection, which is always not null. It can be empty but never null.

Try this:

if (Addresses.Any(x => String.Format("{0} {1}", x.paon.Trim(), x.saon.Trim()) == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo))
{
matchingAddress = Addresses.Where(x => String.Format("{0} {1}", x.paon.Trim(), x.saon.Trim()) == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo).FirstOrDefault();
}

It will check if there is any matching item.

You can try this in your second if:

  if (Addresses.Where(x => String.Format("{0} {1}", x.paon.Trim(), x.saon.Trim()) == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo).FirstOrDefault() != null) { matchingAddress = Addresses.Where(x => String.Format("{0} {1}", x.paon.Trim(), x.saon.Trim()) == person.AddressLineOne && x.thorofare.Trim() == person.AddressLineTwo).FirstOrDefault(); } 

The 'Addresses.Where(filter)' return null is impossible. when all element in IEnumerable<T> not satisfied the where filter, It would be return empty IEnumerable<T>

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