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

时间:2015-01-04 09:59:30

标签: c# linq reflection

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

假设需要使用反射。

你是否知道我必须使用的是带有注释的字符串" //伪代码"下面?感谢。

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

3 个答案:

答案 0 :(得分:2)

您可以传递另一个获取属性值的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;
}

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

如果您想使用反思,请see the answer here

答案 1 :(得分:0)

我已经解决了这个问题:

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

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

答案 2 :(得分:0)

这是&#34; How do I create an expression tree to represent 'String.Contains("term")' in C#?几乎重复的问题。&#34; 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;

}

自&#34; GetExpression&#34;是通用的,除了Client之外,您可以轻松地将其重用于其他类型。考虑重命名方法,因为&#34; GetExpression&#34;没有说出你的意图 - 也许是像#34; GetPropertyContainsExpression&#34;。如果propertyName中的值不是类型上的有效属性,并且指定的属性不是类型为string的{​​{1}},那么您可能还会考虑向该方法添加一些错误处理,这可能不会有采用字符串的Contains方法。这些类型的错误可能很难从表达式构建器在运行时抛出的异常中找出。