C# 基于KeyValuePairs的筛选器列表
我有一个列表,我想根据KeyValuePairs列表进行筛选。KeyValuePair中的所有键都存在于对象中 假设我有一个类中的对象列表:C# 基于KeyValuePairs的筛选器列表,c#,lambda,C#,Lambda,我有一个列表,我想根据KeyValuePairs列表进行筛选。KeyValuePair中的所有键都存在于对象中 假设我有一个类中的对象列表: public class filters { public string Name { get; set; } public string Age { get; set; } public string Country { get; set; } } 我有一个KeyValuePair,带有: Key: "Name", Value:
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生成某种类型的LINQ谓词,该谓词可用作列表。其中(谓词)
,谓词将与我编写的列表相同。其中(c=>c.Name==“test”&&c.Country==“SE”)
或者我应该如何处理这个问题?我可能在这里误解了您的意思,但这是否符合您的要求:
// 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"];
像这样的?通过反射获取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);
Func过滤器=(过滤器,成对)=>
{
foreach(var valuePair成对)
{
if(filters.GetType().GetProperty(valuePair.Key).GetValue(filters)!=valuePair.Value)
{
返回false;
}
}
返回true;
};
列表=新列表();
添加(新过滤器(){Name=“Name1”,Country=“DE”});
添加(新过滤器(){Name=“Name2”,Country=“SE”});
var element=list.FirstOrDefault(x=>filter(x,new list()){
新的KeyValuePair(“名称”、“名称2”),
新的KeyValuePair(“国家”、“SE”),
}));
Console.WriteLine(element.Name);
这应该可以做到:
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;
}
void Main()
{
列表过滤器=新列表(){
新筛选器{Name=“Filter1”,Age=1,Country=“De”},
新筛选器{Name=“Filter2”,年龄=2,国家/地区=“Fr”},
新筛选器{Name=“Filter3”,Age=3,Country=“It”},
新筛选器{Name=“Filter4”,Age=4,Country=“Es”},
};
KeyValuePair kvp=新的KeyValuePair(“过滤器1”、“De”);
var result=filters.AsQueryable().Where(GetPredicate(kvp));
result.Dump();
}
//将谓词创建为表达式,该表达式以筛选器作为输入,以kvp作为参数
私有静态表达式GetPredicate(KeyValuePair kvp)
{
返回(f)=>f.Name==kvp.Key和&f.Country==kvp.Value;
}
结果:
您需要一个从KeyValuePair生成的
谓词,它是IEnumerable
。所以是
Func<IEnumerable<KeyValuePair<string, string>>, Predicate<filters>>
作为一个班轮:
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));
var filters=新字典{{“Name”,“test”},{“Country”,“SE”};
var result=list.Where(item=>filters.All(f=>(string)(item.GetType().GetProperty(f.Key)?.GetValue(item))==f.Value));
这使您可以拥有无限数量的过滤器
对于列表中的每个项
,All
谓词将检查每个筛选器的有效性item.GetType()
获取项的类型(即关于类的信息)GetProperty(f.Key)
获取特定属性的信息,该属性由当前过滤器f
的键命名GetValue(item)
获取当前项的属性值。?
是c#6的一个新特性,即它是对null
的内联检查,即如果找不到属性,它不会尝试执行GetValue
——这将引发NullReferenceException
——但返回null
。然后必须将属性值强制转换为字符串
,并将其与当前筛选器的值
进行比较。您还可以使用String::Compare(或您喜欢的任何其他比较方法)
All
仅在满足所有筛选条件时返回true
,否则返回false。因此,此查询的结果将包含满足词典中所有筛选器的所有元素您可以使用以下方法:
void Main()
{
var keyValuePairs = new List<KeyValuePair>
{
new KeyValuePair {Key = "Name", Value = "Test"},
new KeyValuePair {Key = "Age", Value = "42"},
new KeyValuePair {Key = "Country", Value = "USA"}
};
var list = new List<Filter>();
list.Add(new Filter { Name = "Test", Age = "42", Country = "USA" });
list.Where(keyValuePairs.ToPredicate<Filter>()).Dump();
}
public class Filter
{
public string Name { get; set; }
public string Age { get; set; }
public string Country { get; set; }
}
public class KeyValuePair
{
public string Key { get; set; }
public string Value { get; set; }
}
public static class KeyValuePairExtensions
{
public static Func<T, bool> ToPredicate<T>(this IEnumerable<KeyValuePair> keyValuePairs)
{
if (keyValuePairs == null || !keyValuePairs.Any())
return t => false; // default value in case the enumerable is empty
var parameter = Expression.Parameter(typeof(T));
var equalExpressions = new List<BinaryExpression>();
foreach (var keyValuePair in keyValuePairs)
{
var propertyInfo = typeof(T).GetProperty(keyValuePair.Key);
var property = Expression.Property(parameter, propertyInfo);
var value = Expression.Constant(keyValuePair.Value, propertyInfo.PropertyType);
var equalExpression = Expression.Equal(property, value);
equalExpressions.Add(equalExpression);
}
var expression = equalExpressions.First();
if (equalExpressions.Count > 1)
{
// combine expression with and
expression = Expression.AndAlso(equalExpressions[0], equalExpressions[1]);
for (var i = 2; i < equalExpressions.Count; i++)
{
expression = Expression.AndAlso(expression, equalExpressions[i]);
}
}
var lambda = (Func<T, bool>)Expression.Lambda(expression, parameter).Compile();
return lambda;
}
}
void Main()
{
var keyValuePairs=新列表
{
新的KeyValuePair{Key=“Name”,Value=“Test”},
新的KeyValuePair{Key=“Age”,Value=“42”},
新的KeyValuePair{Key=“Country”,Value=“USA”}
};
var list=新列表();
添加(新过滤器{Name=“Test”,Age=“42”,Country=“USA”});
list.Where(keyValuePairs.ToPredicate()).Dump();
}
公共类过滤器
{
公共字符串名称{get;set;}
公共字符串年龄{get;set;}
公共字符串国家{get;set;}
}
公共类KeyValuePair
{
公共字符串密钥{get;set;}
公共字符串值{get;set;}
}
公共静态类keyValuePairex
{
public static funct ToPredicate(此IEnumerable keyValuePairs)
{
if(keyValuePairs==null | |!keyValuePairs.Any())
return t=>false;//枚举为空时的默认值
var参数=表达式参数(typeof(T));
var equalExpressions=新列表();
foreach(keyValuePairs中的var keyValuePair)
{
var propertyInfo=typeof(T).GetProperty(keyValuePair.Key);
var property=Expression.property(参数,propertyInfo);
var value=Expression.Constant(keyValuePair.value,propertyInfo.PropertyType);
var equalExpression=表达式.Equal(属性、值);
equalExpressions.Add(equalExpression);
}
var expression=equalExpressions.First();
如果(equalPressions.Count>1)
{
//将表达与和结合起来
expression=expression.AndAlso(相等表达式[0],相等表达式[1]);
对于(变量i=2;i
您还可以扩展ToPredicate
方法,将KeyValuePairs
与和
之外的其他内容结合起来。您是否尝试过反射?不确定我将如何使用反射来处理此var keySet=new Dictionary{{“Name”,“test”};谓词条件=(c)=>c.Name==keySet[“Name”]&&c.Country==keySet[“Co”
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);
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));
void Main()
{
var keyValuePairs = new List<KeyValuePair>
{
new KeyValuePair {Key = "Name", Value = "Test"},
new KeyValuePair {Key = "Age", Value = "42"},
new KeyValuePair {Key = "Country", Value = "USA"}
};
var list = new List<Filter>();
list.Add(new Filter { Name = "Test", Age = "42", Country = "USA" });
list.Where(keyValuePairs.ToPredicate<Filter>()).Dump();
}
public class Filter
{
public string Name { get; set; }
public string Age { get; set; }
public string Country { get; set; }
}
public class KeyValuePair
{
public string Key { get; set; }
public string Value { get; set; }
}
public static class KeyValuePairExtensions
{
public static Func<T, bool> ToPredicate<T>(this IEnumerable<KeyValuePair> keyValuePairs)
{
if (keyValuePairs == null || !keyValuePairs.Any())
return t => false; // default value in case the enumerable is empty
var parameter = Expression.Parameter(typeof(T));
var equalExpressions = new List<BinaryExpression>();
foreach (var keyValuePair in keyValuePairs)
{
var propertyInfo = typeof(T).GetProperty(keyValuePair.Key);
var property = Expression.Property(parameter, propertyInfo);
var value = Expression.Constant(keyValuePair.Value, propertyInfo.PropertyType);
var equalExpression = Expression.Equal(property, value);
equalExpressions.Add(equalExpression);
}
var expression = equalExpressions.First();
if (equalExpressions.Count > 1)
{
// combine expression with and
expression = Expression.AndAlso(equalExpressions[0], equalExpressions[1]);
for (var i = 2; i < equalExpressions.Count; i++)
{
expression = Expression.AndAlso(expression, equalExpressions[i]);
}
}
var lambda = (Func<T, bool>)Expression.Lambda(expression, parameter).Compile();
return lambda;
}
}