【问题标题】:How do I dynamically create an Expression<Func<MyClass, bool>> predicate with string parameter?如何使用字符串参数动态创建 Expression<Func<MyClass, bool>> 谓词?
【发布时间】:2021-02-16 02:59:10
【问题描述】:

我有以下 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;

这可能吗?感谢您提前提供任何帮助。????

【问题讨论】:

  • 也许Dictionary&lt;string, Expression&lt;Func&lt;Contact, bool&gt;&gt;&gt; 包含属性名称和相应的表达式?如果它真的是动态的,你可能需要用 Roslyn 编译它
  • 嗨,你想用它实现什么?你想设置不同的正则表达式来动态检查手机吗?
  • 我打算用这个代码创建一个实用函数,它接受一个参数并返回另一个函数中使用的构建表达式。
  • Charlieface,你能提供一个如何用 Roslyn 编译的例子吗?谢谢。
  • 可能是 DynamicLinq 的一种情况,但不确定解析器将如何处理 First(),因为我从未使用过它

标签: c# expression predicate


【解决方案1】:

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

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

【讨论】:

  • timur,谢谢上面的例子。但是,它没有给我想要的类型 Expression>。我可以更改什么以获得正确的返回类型?再次感谢您的帮助。
  • 你可能会注意到它是异步运行的,所以返回类型是 Task&lt;bool&gt; 但我想你可以制作一个表达式来等待结果,如果需要的话
猜你喜欢
  • 2011-07-02
  • 2010-10-25
  • 1970-01-01
  • 1970-01-01
  • 2021-06-17
  • 2013-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多