简体   繁体   中英

How do I dynamically create an Expression<Func<MyClass, bool>> predicate with string parameter?

I have the follow C# classes

public class Contact
{
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public List<Phone> Phones  { get; set; }
}

public class Phone
{
    public string AreaCode { get; set; }
    public string PhoneNumber { get; set; }
    public bool IsMobile { get; set; }
}

Below is a sample Expression I'm trying to create dynamically.

Expression<Func<Contact, bool>> isMobileExpression = p => p.Phone.First().IsMobile;

I would like to create an Expression like the one above but dynamically define the "p.Phone.First().IsMobile" expression instead of hardcoding it. For example:

var paraName = "p => p.Phone.First().IsMobile";
Expression<Func<Contact, bool>> isMobileExpression = p => paraName;

Is that possible to do? Thanks for any help in advance.

You could consider a CSharpScript :

public class Contact
{
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    public List<Phone> Phones { get; set; }
}

public class Phone
{
    public string AreaCode { get; set; }
    public string PhoneNumber { get; set; }
    public bool IsMobile { get; set; }
}

void Main()
{
    var code = "return Phones.First().IsMobile;";   
    var script = CSharpScript.Create<bool>(code, globalsType: typeof(Contact), options: ScriptOptions.Default.WithReferences("System.Linq").WithImports("System.Linq"));
    var scriptRunner = script.CreateDelegate();
    Console.WriteLine(scriptRunner(new Contact() { Phones = new List<Phone> { new Phone {IsMobile = true }}} ));    
    Console.WriteLine(scriptRunner(new Contact() { Phones = new List<Phone> { new Phone {IsMobile = false }}} ));   
}

UPD

If you want an expression, you could wrap the ScriptRunner delegate into Expression.Call() like so:

Expression<Func<Contact, Task<bool>>> GetExpression()
{
    var code = "return Phones.First().IsMobile;";
    var script = CSharpScript.Create<bool>(code, globalsType: typeof(Contact), options: ScriptOptions.Default.WithReferences("System.Linq").WithImports("System.Linq"));
    var scriptRunner = script.CreateDelegate();
    var p = Expression.Parameter(typeof(Contact));
    var mi = scriptRunner.Method;
    return Expression.Lambda<Func<Contact, Task<bool>>>(Expression.Call(Expression.Constant(scriptRunner.Target), mi, p, Expression.Constant(CancellationToken.None)), p);
}

then you would compile and use it as you see fit:

void Main()
{
    var scriptRunner = GetExpression().Compile();
    Console.WriteLine(scriptRunner(new Contact() { Phones = new List<Phone> { new Phone { IsMobile = true } } }));
    Console.WriteLine(scriptRunner(new Contact() { Phones = new List<Phone> { new Phone { IsMobile = false } } }));
}

I however feel that this is a bit too convoluted. Would probably be easier if you could use the delegate directly.

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