我想构建一个函数,用户可以搜索列表中的某些属性是否包含值
假设我们将拥有List,公司将被定义为具有以下属性的类:
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public string CompanyAddress1 { get; set; }
public string CompanyPostCode { get; set; }
public string CompanyCity { get; set; }
public string CompanyCounty { get; set; }
}
现在 - 理想情况下我想使用这个参数
List<Company> FilterCompanies(List<Company> unfilteredList, string fieldToQueryOn, string query)
{
// linq version what ideally would like to archeve
return unfilteredList.Where(x => x."fieldToQueryOn".ToString().ToLower().Contains(query.ToLower())).ToList();
}
并致电:
var variable = FilterCompanies(NotNullFilledUnfilteredList, "CompanyCity", "New York")
我尝试按照docs.microsoft.com上的教程进行操作,这很容易,但我不知道如何使用对Type的反射扩展该解决方案并在表达式树中使用它。
答案 0 :(得分:5)
泛型和lambda:
namespace WhereTest
{
class Program
{
static void Main(string[] args)
{
var companies = new[] { new Company { Id = 1, Name = "abc" }, new Company { Id = 2, CompanyAddress1 = "abc" } };
foreach (var company in FilterCompanies(companies, "abc", x => x.Name, x => x.CompanyCity))
{
Console.WriteLine(company.Id);
}
}
static List<Company> FilterCompanies(IEnumerable<Company> unfilteredList, string query, params Func<Company, string>[] properties)
{
return unfilteredList.Where(x => properties.Any(c => c.Invoke(x) == query)).ToList();
}
}
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public string CompanyAddress1 { get; set; }
public string CompanyPostCode { get; set; }
public string CompanyCity { get; set; }
public string CompanyCounty { get; set; }
}
}
优点:没有反射,强类型代码。
答案 1 :(得分:4)
您可以使用Type.GetProperty
按名称使用反射查找属性,然后使用GetValue
检索值:
List<Company> FilterCompanies(List<Company> list, string propertyName, string query)
{
var pi = typeof(Company).GetProperty(propertyName);
query = query.ToLower();
return list
.Where(x => pi.GetValue(x).ToString().ToLower().Contains(query))
.ToList();
}
如果有人使用无效的属性,您应该添加一些错误处理。例如,您可以(pi?.GetValue(x) ?? string.Empty).ToString().ToLower()…
安全地使用。
我还将query.ToLower()
移出了lambda表达式,以确保它只运行一次。您还可以尝试其他不区分大小写的方法来检查query
是否是值的子字符串,以避免必须转换任何字符串。有关详细信息,请查看问题“Case insensitive 'Contains(string)'”。
顺便说一下。如果您通常对运行动态查询感兴趣,则应该查看dynamic LINQ。
答案 2 :(得分:0)
您可以将GetProperty与GetValue
结合使用List<Company> FilterCompanies(List<Company> unfilteredList, string fieldToQueryOn, string query)
{
return unfilteredList
.Where(x => x.GetType.GetProperty(fieldToQueryOn).GetValue(x)
.ToString().ToLower().Contains(query.ToLower())).ToList();
}
或:property accessors using string(与javascript obj[property]
相同)
您可以修改您的课程:
public class Company
{
// just add this code block to all your classes that would need to access
// your function
public object this[string propertyName]
{
get{
Type myType = typeof(Company);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
return myPropInfo.GetValue(this, null);
}
set{
Type myType = typeof(Company);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
myPropInfo.SetValue(this, value, null);
}
}
public int Id { get; set; }
public string Name { get; set; }
public string CompanyAddress1 { get; set; }
public string CompanyPostCode { get; set; }
public string CompanyCity { get; set; }
public string CompanyCounty { get; set; }
}
然后您可以像这样更改您的功能:
List<Company> FilterCompanies(List<Company> unfilteredList, string key, string query)
{
// linq version what ideally would like to archeve
return unfilteredList.Where(x => x[key].ToString().ToLower().Contains(query.ToLower())).ToList();
}
选中此Demo
注意:强>
为了使您的功能正常工作,您需要将此代码添加到您的类中:
public object this[string propertyName]
{
get{
Type myType = typeof(<YOUR CLASS HERE>);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
return myPropInfo.GetValue(this, null);
}
set{
Type myType = typeof(<YOUR CLASS HERE>);
PropertyInfo myPropInfo = myType.GetProperty(propertyName);
myPropInfo.SetValue(this, value, null);
}
}
加分:您现在可以使用myObject["someproperty"]
检索值,甚至可以设置其值!