[英]Linq query - “Where” on List<T> Where reflected property Contains text/value
我想建立一個函數,用戶可以在其中搜索列表中的某些屬性是否包含值
假設我們將擁有List,並且Company將被定義為具有以下屬性的類:
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上的教程,這很容易,但是我不知道如何擴展對類型的反射並在表達式樹中使用該解決方案。
泛型和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; }
}
}
優點:無反射,強類型代碼。
您可以使用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
是價值的子串,以避免任何字符串轉換。 有關更多信息,請查看問題“不區分大小寫的'包含(字符串)'” 。
順便說一句。 如果您通常對運行動態查詢感興趣,則應該看看動態LINQ 。
您可以結合使用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();
}
OR: 使用字符串的屬性訪問器 (與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();
}
檢查這個演示
注意:
為了使函數正常工作,您需要將此代碼添加到您的類中:
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"]
檢索值,甚至可以設置其值!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.