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

xqnpmsa8  于 2022-12-06  发布在  C#
关注(0)|答案(2)|浏览(262)
public class Sample
{
    public int Id { get; set; }
    public string Description { get; set; }
    public DateTime EffectiveDate { get; set; }
}

IEnumerable<Sample> sampleList;
//Populate the list

现在我想用“Id”属性过滤列表,有时用“Description”属性过滤列表。只想将属性名(filterColumn)和属性值(filterValue)都作为字符串传递。
我尝试了以下方法:

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

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

第二个选项工作,如果我传递filterColumn作为“描述”,但抛出不兼容的'='操作符之间的字符串和整数错误时,“Id”作为filterColumn和一些filterValue如“1”传递。
感谢你的帮助谢谢

aelbi1ox

aelbi1ox1#

你的第一种方法可以奏效。扩展乔恩·斯基特的评论,这里是调整后的陈述。

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

要了解这一点,必须考虑到不同的数据类型。至少可以通过两种方式做到这一点:使用泛型方法或使用对象数据类型。为了便于说明,我将使用对象方法。

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

IEnumerable<Sample> sampleList;

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

这个例子并不安全,因为没有类型检查来确保属性值与您传递的数据类型相同。例如,没有什么可以阻止您传递“Description”和100作为参数。您不能在整数和字符串之间进行有意义的比较,因此您总是得到一个空结果。Equals方法不会抛出异常,它只是看到两个对象是不同的。正如Jon指出的,在这种情况下,您总是希望使用Equals而不是“==”操作符。Equals方法用于比较内容,而“==”用于比较引用。示例:

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)

另外,注意字符串在使用“==”运算符时有一些特殊的行为。(容器)和内容。您要比较内容,这意味着等于。(我注意到VisualStudio中的“立即”窗口在使用“=="时关于字符串的结果不一致。我怀疑这是因为字符串引用可以是,但并不总是在该窗口中优化。)
您说您的第二种方法有效。我在标准的IEnumerable.Where方法中没有看到过这种类型的筛选字符串。所以我猜您正在使用一些扩展。您的示例并不像下面所示的那样工作。DataTable类使用与您的用法相匹配的筛选字符串。通常,筛选字符串必须根据数据类型以不同的方式构造。例如,字符串需要引号(您已经有了),但整数值不使用引号。

pgvzfuti

pgvzfuti2#

另一个选项是使用所需的操作设置字典。

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));
}

这样做的优点是可以执行更复杂的比较,例如按值的范围或包含多个特性的范围添加自定义过滤器。

相关问题