Asela Gunawardena
Asela Gunawardena

Reputation: 113

Dynamic C# expression that Selects from given List, containing a given value

I Have the following Object structure

public class Client
{
    public Client()
    {
        Identifiers = new List<ExternalIdentifier>();
    }

    public Guid? PatientId { get; set; }
    .
    .

    public IList<ExternalIdentifier> Identifiers { get; set; }
}

And I would like to build the following a Dynamic Expression,

Clients.Where(s=>s.Identifiers.Select(a=>a.Value).ToList().Contains("d"));

Here is what i Have so far

public Expression GeneratExp(string consVal)
{
    //TODO be removed  .Where(s=>s.Identifiers.Select(a=>a.Value).ToList().Contains("d"));

    ParameterExpression externalId = Expression.Parameter(typeof(ExternalIdentifier), "id");
    Expression idProperty = Expression.PropertyOrField(externalId, "Value");

    var valueSelector = Expression.Lambda<Func<ExternalIdentifier, string>>(idProperty, new ParameterExpression[] { externalId });

    ParameterExpression client = Expression.Parameter(typeof(Models.Entities.Client), "s");
    Expression id = Expression.PropertyOrField(client, "Identifiers");

    var selM = typeof(Enumerable).GetMethods().First(x => x.Name == "Select").MakeGenericMethod(typeof(ExternalIdentifier), typeof(string));
    var selExpression = Expression.Call(null, selM, id, valueSelector);

    var toli = typeof(Enumerable).GetMethods().First(x => x.Name == "ToList").MakeGenericMethod(typeof(string));
    var toliexp = Expression.Call(null, toli, selExpression);

    var cont = typeof(Enumerable).GetMethods().First(x => x.Name == "Contains").MakeGenericMethod(typeof(string));
    var contexp = Expression.Call(null, cont, toliexp, Expression.Constant("d"));

    var retcontexp = Expression.Lambda<Func<Models.Entities.Client, bool>>(contexp, Expression.Parameter(typeof(Models.Entities.Client), "s"));

    return retcontexp; 
}

when i run the unit tests it builds the following expression s.Identifiers.Select(a=>a.Value).ToList().Contains("d")

but that doesn't execute since "s" i not defined, Any help to build the following is much appreciated.

s => s.Identifiers.Select(a=>a.Value).ToList().Contains("d") is much appreciated

Thanks in advance.

Upvotes: 1

Views: 222

Answers (1)

Kirill Shlenskiy
Kirill Shlenskiy

Reputation: 9587

You are very, very close to getting the desired result. You just need to use the same ParameterExpression instance argument for your Expression.Lambda<TDelegate> factory method that you used when you defined the expression body. Change the last line of your method before return to:

var retcontexp = Expression.Lambda<Func<Client, bool>>(contexp, client);

... and the resulting lambda will be valid and you'll be able to compile it.

Upvotes: 1

Related Questions