简体   繁体   English

C#Linq筛选器IEnumerable动态属性和值

[英]C# Linq Filter IEnumerable dynamic property and value

public class Sample
{
public int Id { get; set; }
public string Description { get; set; }
public DateTime EffectiveDate { get; set; }
}

IEnumberable<Sample> sampleList;
//Populate the list

Now i want to filter the list some times by "Id" property, sometimes "Description" property. 现在,我想通过“ Id”属性有时甚至“ Description”属性来过滤列表。 Just want to pass the property name (filterColumn) and property value (filterValue) both as strings . 只想将属性名称(filterColumn)和属性值(filterValue)都传递为string。

I tried the following: 我尝试了以下方法:

IEnumerable<Sample> result = sampleList.Where(x => x.GetType().GetProperty(filterColumn).Name == filterValue);

AND

string whereQuery = string.Format(" {0} = \"{1}\"", filterColumn, filterValue);
IEnumerable<Sample> result = sampleList.AsQueryable().Where(whereQuery);

The second option works, if i pass the filterColumn as "Description", but throws incomptable '=' operator between string and int error when "Id" is passed as filterColumn and some filterValue like "1". 第二个选项有效,如果我将filterColumn传递为“ Description”,但是当将“ Id”作为filterColumn和一些filterValue(如“ 1”)传递时,在字符串和int错误之间抛出了不可兼容的'='运算符。

Appreciate any help. 感谢任何帮助。 Thanks 谢谢

Your first approach can work. 您的第一种方法可行。 Expanding on Jon Skeet's comment, here's the adjusted statement. 扩展Jon Skeet的评论,以下是调整后的声明。

IEnumerable<Sample> result = sampleList.Where(
  x => x.GetType().GetProperty(filterColumn).GetValue(x, null).Equals(filterValue)
);

To put a little context around this, you would have to allow for the differing data types. 要对此进行一些介绍,您必须允许使用不同的数据类型。 You can do this at least two ways: use a generic method or use the object data type. 您可以通过至少两种方式执行此操作:使用通用方法或使用对象数据类型。 For illustrative purposes, I'll use the object approach. 出于说明目的,我将使用对象方法。

public IEnumerable<Sample> GetFiltered(
  IEnumerable<Sample> samples, string filtercolumn, object filtervalue
{ 
   return samples.Where(
      x => x.GetType().GetProperty(filtercolumn).GetValue(x, null).Equals(filtervalue)
   );
}

IEnumberable<Sample> sampleList;

var byId = GetFiltered(sampleList, "Id", 100);
var byDescription = GetFiltered(sampleList, "Description", "Some Value");

This example is not really safe as there is no type checking to ensure that the property value will be of the same data type that you are passing in. For example, there is nothing stopping you from passing "Description" and 100 as parameters. 此示例并不十分安全,因为没有类型检查来确保属性值将与您传入的数据类型相同。例如,没有什么阻止您传递“ Description”和100作为参数。 You can't do a meaningful comparison between an integer and a string so you will always come up with an empty result. 您无法在整数和字符串之间进行有意义的比较,因此您总是会得出空的结果。 The Equals method does not throw an exception, it just sees that the two objects are different. Equals方法不会引发异常,它只是看到两个对象是不同的。 As Jon pointed out, you'll always want to use Equals in this case rather than the "==" operator. 正如Jon所指出的,在这种情况下,您总是要使用Equals而不是“ ==”运算符。 The Equals method is intended to compare content while "==" compares references. Equals方法用于比较内容,而“ ==“用于比较引用。 Example: 例:

Console.WriteLine(12 == 12); 
// True

object a = 12;
object b = 12;

Console.WriteLine(a == b); 
// False - because, due to boxing, a and b are separate objects
// that happen to contain the same value. (Check out "boxing" 
// if this doesn't make sense.)

Console.WriteLine(a.Equals(b)); 
// True - because the Equals method compares content (value)

Also, note that strings have some special behaviors when using the "==" operator. 另外,请注意,使用“ ==”运算符时,字符串具有某些特殊行为。 The important thing to remember is that there is a difference between references (containers) and content. 要记住的重要一点是,引用(容器)和内容之间存在差异。 You want to compare content and that means Equals. 您要比较内容,这意味着等于。 (I have noticed that the Immediate window in Visual Studio is inconsistent in its results regarding strings when using "==". I suspect this is because string references can be, but are not always, optimized in that window.) (我已经注意到,在使用“ ==”时,Visual Studio中的即时窗口与字符串有关的结果不一致。我怀疑这是因为可以在该窗口中(但并非总是)优化字符串引用。)

You state that your second approach works. 您声明第二种方法可行。 I have not seen this type of filter string in a standard IEnumerable.Where method. 我没有在标准IEnumerable.Where方法中看到这种类型的过滤器字符串。 So I am guessing that you are using some extensions. 所以我猜您正在使用一些扩展。 Your example does not work as shown. 您的示例不起作用,如图所示。 The DataTable class uses filter strings that match your usage. DataTable类使用与您的用法匹配的过滤器字符串。 In general, a filter string has to be constructed in different ways based on data type. 通常,必须根据数据类型以不同的方式构造过滤器字符串。 For example, a string requires the quotes (which you have) but an integer value does not use quotes. 例如,字符串需要用引号引起来,而整数值不使用引号。

Another option that you have is to set up a dictionary with the required operations. 您拥有的另一个选择是使用所需的操作来设置字典。

public IEnumerable<Sample> GetFiltered(
    IEnumerable<Sample> samples, string property, string value)
{
    var map = new Dictionary<string, Func<string, Func<Sample, bool>>>()
    {
        { "Description", v => s => s.Description == v },
        { "Id", v => s => s.Id == int.Parse(v) },
    };
    return samples.Where(map[property](value));
}

The advantage here is that you can perform a more complex comparison, such as adding custom filters by ranges of values, or those containing more than one property. 这样做的好处是您可以执行更复杂的比较,例如按值范围或包含多个属性的值范围添加自定义过滤器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM