[英]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.