我有一个列表,我想根据KeyValuePairs列表进行过滤。 KeyValuePair中的所有键都存在于对象中。
所以,让我说我有一个来自这个类的对象列表:
public class filters
{
public string Name { get; set; }
public string Age { get; set; }
public string Country { get; set; }
}
我有一个KeyValuePair:
Key: "Name", Value: "test"
Key: "Country", Value: "SE"
是否可以从KeyValuePair生成某种可用作list.Where(predicate)
的LINQ谓词,谓词与我写list.Where(c => c.Name == "test" && c.Country == "SE")
时的谓词相同?
或者我该如何处理?
答案 0 :(得分:1)
作为一个单行:
var filters = new Dictionary<string, string>{{"Name", "test"}, {"Country", "SE"}};
var result = list.Where(item => filters.All(f => (string)(item.GetType().GetProperty(f.Key)?.GetValue(item)) == f.Value));
这使您可以拥有无限数量的过滤器。
对于item
中的每个list
,All
谓词都会检查每个过滤器的有效性。 item.GetType()
获取Type
的{{1}}(即有关您班级的信息)。 item
获取特定属性的信息,该信息以当前过滤器GetProperty(f.Key)
的{{1}}命名。 Key
获取当前f
的属性值。 GetValue(item)
是c#6的新功能,即它是item
的内联检查,即如果找不到该属性,则不会尝试执行?
- 这会引发null
- 但返回GetValue
。然后,您必须将属性值强制转换为NullReferenceException
,并将其与当前过滤器的null
进行比较。您还可以使用String :: Compare(或您喜欢的任何其他比较方法)。
string
仅返回Value
,否则返回false。因此,此查询的结果将包含符合词典中所有过滤器的所有元素
答案 1 :(得分:0)
我可能在这里误解了你,但这样做是你想要的:
// say I have a list of ilters like this
// assume there are actually some filters in here though
var filterCollection = new List<filters>()
// build dictionary of key values
var keyedSet = filterCollection.ToDictionary(i => i.Name + i.Country, i => i);
// query them using key ...
var filterItem = keyedSet["testSE"];
...或者您可以将谓词包装在扩展方法中......
public IEnumerable<filters> ByNameAndCountry(this IEnumerable<filters> collection, string name, string country)
{
return collection.Where(i => i.Name == name && i => i.Country == country);
}
...完成后你可以像这样过滤原始列表......
var result = filterCollection.ByNameAndCountry("test", "ES");
答案 2 :(得分:0)
这样的东西?通过反思获得Propertyname并进行相等检查。
Func<filters, IEnumerable<KeyValuePair<string, string>>, bool> filter = (filters, pairs) =>
{
foreach (var valuePair in pairs)
{
if (filters.GetType().GetProperty(valuePair.Key).GetValue(filters) != valuePair.Value)
{
return false;
}
}
return true;
};
List<filters> list = new List<filters>();
list.Add(new filters() { Name = "Name1", Country = "DE"});
list.Add(new filters() { Name = "Name2", Country = "SE"});
var element = list.FirstOrDefault(x => filter(x, new List<KeyValuePair<string, string>>() {
new KeyValuePair<string, string>("Name", "Name2"),
new KeyValuePair<string, string>("Country", "SE"),
}));
Console.WriteLine(element.Name);
答案 3 :(得分:0)
这应该可以解决问题:
void Main()
{
List<Filter> filters = new List<Filter>() {
new Filter {Name = "Filter1", Age = 1, Country ="De"},
new Filter {Name = "Filter2", Age = 2, Country ="Fr"},
new Filter {Name = "Filter3", Age = 3, Country ="It"},
new Filter {Name = "Filter4", Age = 4, Country ="Es"},
};
KeyValuePair<string, string> kvp = new KeyValuePair<string, string>("Filter1", "De");
var result = filters.AsQueryable().Where (GetPredicate(kvp));
result.Dump();
}
//Create the predicate as an expression, which takes a Filter as input and a kvp as a parameter
private static Expression<Func<Filter, bool>> GetPredicate(KeyValuePair<string,string> kvp)
{
return (f) => f.Name == kvp.Key && f.Country == kvp.Value;
}
结果:
答案 4 :(得分:0)
您希望从KeyValuePair生成Predicate<filters>
,即IEnumerable<KeyValuePair<string, string>>
。所以它是
Func<IEnumerable<KeyValuePair<string, string>>, Predicate<filters>>
使用反射枚举KeyValuePair.Key中列出的All
属性,并检查每个属性值是否与KeyValuePair.Value匹配。完整代码就像
var lists = new List<filters> { new filters { Name = "abc", Country = "def" } };
Func<IEnumerable<KeyValuePair<string, string>>, Predicate<filters>> predicateBuilder =
( keyValueParis ) => filter => ( from kp in keyValueParis
let pi = typeof( filters ).GetProperty( kp.Key )
select pi.GetValue( filter ) == kp.Value )
.All( r => r );
var predicates = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("Name", "abc" ),
new KeyValuePair<string, string>("Country", "def")
};
Predicate<filters> predicate = predicateBuilder( predicates );
Console.WriteLine( lists.FindAll(predicate).Count);
答案 5 :(得分:0)
你可以使用这样的方法:
ToPredicate
您还可以扩展KeyValuePairs
方法,将and
与{{1}}之外的其他内容合并。