Search code examples
linqlambdaexpression-trees

Expression.Condition(nullableType.HasValue, new classInstance(){ ... }, null) can it be done some other way?


I am working on a projection utility and have one last (more?) hurdle to clear...

Here is the scenario:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int? AddressID { get; set; }
    public Address Address { get; set; }
    public string Otherproperty1 { get; set; }
    public string Otherproperty2 { get; set; }
    public string Otherproperty3 { get; set; }
    public string Otherproperty4 { get; set; }
}

public class PersonSummary
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int? AddressID { get; set; }
    public AddressSummary Address { get; set; }

}

public class Address
{
    public int AddressID { get; set; }
    public string HouseNumber { get; set; }
    public string StreetName { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public int Zip { get; set; }
    public string Otherproperty1 { get; set; }
    public string Otherproperty2 { get; set; }
    public string Otherproperty3 { get; set; }
    public string Otherproperty4 { get; set; }
}

public class AddressSummary
{
    public int AddressID { get; set; }
    public string HouseNumber { get; set; }
    public string StreetName { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public int Zip { get; set; }
}

I successfully have my utility working something like this:

ProjectionUtility.Project<Person,PersonSummary>();

Which will return this Expression Lambda:

p => new PersonSummary(){
    FirstName = p.FirstName,
    LastName = p.LastName,
    AddressID = p.AddressID,
    Address = p.AddressID.HasValue
        ? new AddressSummary(){ AddressID = p.Address.AddressID, HouseNumber = p.Address.HouseNumber, etc... }
        : new AddressSummary(){}
}

My goal is to be able to set Address = null if the AddressID.HasValue is false like so:

p => new PersonSummary(){
    FirstName = p.FirstName,
    LastName = p.LastName,
    AddressID = p.AddressID,
    Address = p.AddressID.HasValue
        ? new AddressSummary(){ AddressID = p.Address.AddressID, HouseNumber = p.Address.HouseNumber, etc... }
        : null
}

This is easily done "manually", however when I try to programatically create this lambda using expressions, I'm stuck...

I am currently using what essentially breaks down to this (I know the syntax isn't right, but I did it this way to in an attempt to show what it is I'm doing):

Expression.Condition(
    p.AddressID.HasValue,
    new AddressSummary(){},
    new AddressSummary(){});

If I try this:

Expression.Condition(
    p.AddressID.HasValue,
    new AddressSummary(){},
    null);

I can't because iftrue and iffalse must be the same type (AddressSummary) so I am stuck at the moment creating a new AddressSummary for the iffalse argument.

Any ideas?

Thanks!


Solution

  • You need to cast your null to the correct type. In this case:

    Expression.Condition(
        p.AddressID.HasValue,
        new AddressSummary(){},
        (AddressSummary)null);
    

    null can be any (reference) type, but by default it is of type System.Object. If you want it to be another type, you have to tell it.