2017-05-05 62 views
0

假设我有一个这样的类:如何过滤在LINQ有不同的参数列表

public class SampleClass 
{ 
    public string SampleProperty1 { get; set; } 
    public string SampleProperty2 { get; set; } 
    public string SampleProperty3 { get; set; } 
    public string SampleProperty4 { get; set; } 
    public string SampleProperty5 { get; set; } 
} 

而且我有一个这样的名单:

List<SampleClass> sampleList = new List<SampleClass>(); 

我要过滤通过名单SampleProperty1SampleProperty5。下次我会用SampleProperty3SampleProperty2。我的意思是用户可以过滤他想要的任何属性。

我该如何实现这种灵活性?

我不想编写if语句和属性一样多,因为属性的实际数量更多。

有没有一个聪明的方法来做到这一点?

谢谢。

+0

您需要根据用户选定的过滤器“生成”谓词集合,然后才能将这些谓词应用到列表中。如何根据字段类型和过滤器类型(相等,包含,更大...)生成它们 – Fabio

+0

[LINQ中动态WHERE子句]的可能重复(http://stackoverflow.com/questions/848415/dynamic- where-clause-in-linq) – Pikoh

+0

还有更多... – Pikoh

回答

1

您可以为每个属性构建lambda表达式并使用它过滤集合。 比方说,你有属性名称的Dictionary与要通过筛选自己的价值观:

var filters = new Dictiontionary<string, object>(); 
IEnumerable<SampleClass> query = listOfSampleClasses; 

// we will loop through the filters 
foreach(filter in filters) 
{ 
    // find the property of a given name 
    var property = typeof(SampleClass).GetProperty(filter.Key, BindingFlags.Instance | BindingFlags.Public); 
    if (property == null) continue; 

    // create the ParameterExpression 
    var parameter = Expression.Parameter(typeof(SampleClass)); 
    // and use that expression to get the expression of a property 
    // like: x.SampleProperty1 
    var memberExpression = Expression.Property(parameter, property); 

    // Convert object type to the actual type of the property 
    var value = Convert.ChangeType(filter.Value, property.PropertyType, CultureInfo.InvariantCulture); 

    // Construct equal expression that compares MemberExpression for the property with converted value 
    var eq = Expression.Equal(memberExpression, Expression.Constant(value)); 

    // Build lambda expresssion (x => x.SampleProperty == some-value) 
    var lambdaExpression = Expression.Lambda<Func<SampleClass, bool>>(eq, parameter); 

    // And finally use the expression to filter the collection 
    query = query.Where(lambdaExpression); 
} 

var filteredList = query.ToList(); 

当然,你可以把这些代码的任何类型的一般方法和过滤器内部集合。

对于输入字典,包含两个对:"SampleProperty1" - "foo""SampleProperty2" - "bar" 它会产生类似的东西:

listOfSampleClasses 
    .Where(x => x.SampleProperty1 == "foo") 
    .Where(x => x.SampleProperty2 == "bar"); 
+0

例如,我将这个字符串作为过滤器:'SampleProperty1 = JasonANDSampleProperty2 = Overflow'。我怎样才能将它传递给你的“过滤器”字典。 – jason

+1

首先声明词典:'VAR滤波器=新词典<字符串对象>();'然后添加值:'filters.Add( “SampleProperty1”, “杰森”);''filters.Add( “SampleProperty2”, “溢出”);' – nocodename

+0

不应该'过滤器'是'的类型'然后呢? – jason

1

你可以用这样的条件构建一个LINQ语句。

var query = sampleList; 

if(shouldFilterProperty1) 
{ 
    query = query.Where(x => x.SampleProperty1.Contains(SearchPattern1)); 
} 
if(shouldFilterProperty2) 
{ 
    query = query.Where(x => x.SampleProperty2.Contains(SearchPattern2)); 
} 

var result = query.ToList(); 

这只是前两个属性的一个示例。如果您需要其他检查(而不是Contains),则可以使用相同的样式来执行它们。

+0

所以我需要写ifs与属性一样多? – jason

+0

这只是一种方法。您可以尝试使用反射或更通用的方式来编写它。基数将始终相同:1.检查是否要过滤2.为查询应用新的Where语句。 –

0

如果你有能够改变你SampleClass类的结构奢侈品,那么你可以尝试像以下:

public class SampleClass 
{ 
    public IDictionary<string, string> Properties { get; } 
} 

private static IList<SampleClass> FilterList(IList<SampleClass> list, 
              params Tuple<string, string>[] propertyNames) 
{ 
    // No point filtering here. 
    if (propertyNames == null) 
    { 
     return list; // or null/empty list if you want to match none as the default. 
    } 

    // Match All the property values supplied in the filter, you can change this to 
    // Contains or string.Equals, etc. to suit your matching needs. 
    return list.Where(x => propertyNames.All(p => x.Properties[p.Item1] == p.Item2)) 
       .ToList(); 
} 

用法:

FilterList(sampleList, 
      Tuple.Create("SampleProperty1", "Value1"), 
      Tuple.Create("SampleProperty5", "Value5")); 

这种方法的好处意味着您不需要大量的if语句就可以确定原来要求的Where子句。

1

你可以找到你想要通过反射筛选和使用这种方法来构建LINQ查询性能。

// create your sample list 
List<SampleClass> sampleList = new List<SampleClass>(); 
sampleList.Add(...) 

// create the filter 
Dictionary<string, string> Filter = new Dictionary<string, string>(); 
Filter.Add("SampleProperty1", "SearchPattern1"); 
Filter.Add("SampleProperty5", "SearchPattern5"); 

// create the linq query 
var query = sampleList.AsEnumerable();  
foreach(var filterItem in Filter) 
{ 
    // get the property you want to filter 
    var propertyInfo = typeof(SampleClass).GetProperty(filterItem.Key); 

    // add the filter to your query 
    query = query.Where(x => (string)propertyInfo.GetValue(x) == filterItem.Value); 
} 

// execute the query 
var resultList = query.ToList();