C# 基于KeyValuePairs的筛选器列表

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:

我有一个列表,我想根据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生成某种类型的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;
    }
}