繁体   English   中英

如何在运行时将属性放入linq表达式?

[英]How can I put a property to linq expression at runtime?

我需要通过字符串参数“ propertyName”将属性名称传递给“ GetClientsByFilter()”方法,并在LINQ表达式中使用此属性。

假定需要使用反射。

您是否知道我必须在下面使用带注释“ // pseudo code”的字符串代替什么? 谢谢。

public class Client
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

internal class DataLayer
{
  public static List<Client> GetClientsByFilter(string search, string propertyName)
  {
     //it's Entity Framework context
     using (var dbContext = new LibDbContext())
        {
            List<Client> clients;

                 clients = dbContext.Clients
                .Where(item => item.[propertyName].Contains(search)) // pseudo code
                .ToList();
        }
     return clients;
  }
}

您可以传递另一个获取属性值的lambda而不是属性:

public static List<Client> GetClientsByFilter(string search, 
                                              Func<Client, string> propertyGetter)
{
  //it's Entity Framework context
  using (var dbContext = new LibDbContext())
  {
    List<Client> clients;

    clients = dbContext.Clients
                       .Where(item => propertyGetter(item).Contains(search))
                       .ToList();
  }
  return clients;
}

不幸的是,当您从“外部”获取属性名称时,无法使用此方法,并且无法构建适当的lambda来获取值。 在这种情况下,您可以为每个属性名称准备一个lambda字典。

如果要使用反射,请在此处查看答案

我已经解决了这样的问题:

    public static List<Client> GetClientsByFilter(string search, string propertyName)
    {
        using (var dbContext = new LibDbContext())
        {     
            List<Client> clients;

              switch (propertyName)
              {
                case "LastName":

                  clients = dbContext.Clients
                      .Where(item => item.LastName.Contains(search))
                      .ToList();
                break;

                case "FirstName":

                  clients = dbContext.Clients
                      .Where(item => item.FirstName.Contains(search))
                      .ToList();
                break;
              }
           return clients;
        } 

但是我想重写这段代码,并且无需复制/粘贴即可使其更加清晰

这是一个几乎重复的问题,“ 如何在C#中创建一个表达式树来表示'String.Contains(“ term”)'?” Marc的答案提供了以下代码来构建表达式,这就是您要查找的内容:

static Expression<Func<T, bool>> GetExpression<T>(string propertyName, string propertyValue)
{
    var parameterExp = Expression.Parameter(typeof(T), "type");
    var propertyExp = Expression.Property(parameterExp, propertyName);
    MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
    var someValue = Expression.Constant(propertyValue, typeof(string));
    var containsMethodExp = Expression.Call(propertyExp, method, someValue);

    return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
}

...现在从您的方法中使用它:

public static List<Client> GetClientsByFilter(string search, string propertyName)
{
   //it's Entity Framework context
   using (var dbContext = new LibDbContext())
   {
        List<Client> clients;

             clients = dbContext.Clients
            .Where(GetExpression<Client>(propertyName, search)) // Now using Marc's method
            .ToList();
    }
 return clients;

}

由于“ GetExpression”是通用的,因此除了Client之外,您还可以轻松地将其重用于其他类型。 考虑重命名该方法,因为“ GetExpression”并不能说明您的意图,例如“ GetPropertyContainsExpression”之类的东西。 如果propertyName中的值不是该类型上的有效属性,并且当指定的属性不是string类型(可能没有采用字符串的Contains方法)时,您也可以考虑对该方法添加一些错误处理。 从表达式构建器在运行时可能引发的异常中,可能很难弄清这些错误。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM