Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#,Linq,过滤一个列表,无论其属性是否出现在另一个列表中_C#_Linq - Fatal编程技术网

C#,Linq,过滤一个列表,无论其属性是否出现在另一个列表中

C#,Linq,过滤一个列表,无论其属性是否出现在另一个列表中,c#,linq,C#,Linq,如果一个列表的元素属性出现在另一个列表中,我将尝试筛选该列表。 以下是我的例子: public class Detail { public int Id { get; set; } public string Material { get; set; } public string Title { get; set; } public string Duration { get; set; } publi

如果一个列表的元素属性出现在另一个列表中,我将尝试筛选该列表。 以下是我的例子:

 public class Detail 
    {
        public int Id { get; set; }
        public string Material { get; set; }
        public string Title { get; set; }
        public string Duration { get; set; }
        public string FileName { get; set; }
        public string FileLocation{ get; set; }
        
    }
我有一个
dataList=List()
a
displayList=[“Title”、“Duration”、“FileName”]
和一个
filterString=“test”
对于正常Linq,我们有:

dataList.Where(x x=> x.Title.Contains(filterString) || x.Duration.Contains(filterString) ||x.FileName.Contains(filterString))
但我的任务是以更编程的方式对其进行过滤,如果细节属性出现在displayList上,我想过滤dataList。有什么办法吗

如果
显示列表

不是很优雅,但很直截了当:

dataList.Where(x =>
    displayList.Contains(nameof(Detail.Title)) && x.Title.Contains(filterString) ||
    displayList.Contains(nameof(Detail.Duration)) && x.Duration.Contains(filterString) ||
    ...
)
 

下面的解决方案需要更多的编码,但是可以对每个类和要检查的每个类型重用它

我们不会只针对类细节,也不会只针对过滤器字符串, 我将使其成为
IEnumerable
的通用扩展方法,这样您就可以将其与其他LINQ方法相结合。看

首先我会给出签名,然后我写代码:

就像大多数LINQ函数一样:您可以提供比较器,但不必提供;在这种情况下,将使用默认比较器:

public static IEnumerable<TSource> Filter<TSource, TKey>(
    this IEnumerable<TSource> source,
    IEnumerable<string> propertyNames,
    TKey filterValue)
{
    // only call the overload with a null comparer:
    return Filter(source, propertyNames, filterValue, null);
}

public static IEnumerable<TSource> Filter<TSource, TKey>(
    this IEnumerable<TSource> source,
    IEnumerable<string> propertyNames,
    TKey filterValue,
    IEqualityComparer comparer)
{
    // TODO: exceptions if input null

    if (comparer == null) comparer = EqualityComparer<TKey>.Default;
    
    // TODO: implement
}
有些人不喜欢收益,您也可以继续LINQ语句:

// From every PropertyInfo, make a keySelector, similar to GroupBy
IEnumerable<Func<TSource, TKey>> keySelectors = propertyInfos
    .Select<PropertyInfo, Func<TSource, TKey>> (propertyInfo =>
        x => (TKey)propertyInfo.GetValue(x));
var result = dbLibraryContext.Books
    .Where(book => ...)
    .Select(book => new Detail() {....})
    .Filter(propertyNames, filterValue)
    .GroupBy(detail => detail.Material);
    

您是否在任何属性中搜索
“test”
,该属性的名称在
displayList
中指定(linq中缺少此位)?是@Sinatr,您有什么解决方案吗?谢谢您的评论,但是因为displayList可能会更改,所以我想要一个类似于``dataList.Where(x=>displayList.ForEach(y=>)`` displayList的循环-这不是问题。您只需像我一样对所有属性执行可能出现在
displayList
中的操作。如前所述,这并不优雅。其他人可能会用委托字典或其他东西提供更好的答案。您可以使用反射来获取属性列表并获取它们的值,但这会很慢。尽管这也是一个问题因为你还没有说任何关于性能的事情,所以请不要回答。
// From every PropertyInfo, make a keySelector, similar to GroupBy
IEnumerable<Func<TSource, TKey>> keySelectors = propertyInfos
    .Select<PropertyInfo, Func<TSource, TKey>> (propertyInfo =>
        x => (TKey)propertyInfo.GetValue(x));
// From every KeySelector and the filterValue, create a Predicate, like in Where
IEnumerable<Func<TSource, bool>> predicates = keySelectors
    .Select<Func<TSource, TKey>, Func<TSource, bool>>(
        keySelector => sourceItem => comparer.Equals(keySelector(sourceItem), filterValue));
IEnumerable<TSource> filteredValues = source.Where(sourceItem =>
    predicates.All(predicate => predicate(sourceItem);
return filteredValues;
string filterValue = "Test";
IEnumerable<string> propertyNames = new string[] {"Title", "FileName"};
IEnumerable<Detail> details = ...

IEnumerable<Detail> detailsWithTitleFileNameEqualsTest = details.Filter(
    propertyNames,
    filterValue);
IEnumerable<Detail> detailsWithTitleFileNameEqualsTest = details.Filter(
    propertyNames,
    filterValue,
    StringComparer.OrdinalIgnoreCase);
var result = dbLibraryContext.Books
    .Where(book => ...)
    .Select(book => new Detail() {....})
    .Filter(propertyNames, filterValue)
    .GroupBy(detail => detail.Material);