如何使用字符串参数动态创建 Expression<Func<MyClass, bool>> 谓词?

时间:2021-02-16 02:59:10

标签: c# expression predicate

我有以下 C# 类

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; }
}

以下是我尝试动态创建的示例表达式。

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

我想创建一个类似于上面的表达式,但动态定义“p.Phone.First().IsMobile”表达式而不是对其进行硬编码。 例如:

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

可以这样做吗?提前感谢您的任何帮助。?

1 个答案:

答案 0 :(得分:0)

您可以考虑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 }}} ));   
}

更新

如果你想要一个表达式,你可以像这样将 ScriptRunner 委托包装到 Expression.Call() 中:

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);
}

然后你就可以按照你认为合适的方式编译和使用它:

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 } } }));
}

但是我觉得这有点太复杂了。如果您可以直接使用委托,可能会更容易。

相关问题