C# Linq 筛选器 IEnumerable 动态属性和值
本文关键字:属性 动态 IEnumerable Linq 筛选 | 更新日期: 2023-09-27 17:57:05
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"属性过滤列表,有时按"描述"属性过滤列表。只想将属性名称(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")传递时,字符串和 int 错误之间会抛出不兼容的"="运算符。
感谢任何帮助。谢谢
您的第一种方法可以奏效。扩展Jon Skeet的评论,这是调整后的声明。
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");
此示例并不真正安全,因为没有类型检查来确保属性值与要传入的数据类型相同。例如,没有什么可以阻止您将"描述"和 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)
另请注意,字符串在使用"=="运算符时具有一些特殊行为。 要记住的重要一点是,引用(容器)和内容之间存在差异。您想比较内容,这意味着等于。(我注意到Visual Studio中的即时窗口在使用"=="时关于字符串的结果不一致。我怀疑这是因为字符串引用可以(但并非总是)在该窗口中进行优化。
你说你的第二种方法有效。我还没有在标准的IEnumerable.Where方法中看到这种类型的过滤器字符串。所以我猜你正在使用一些扩展。您的示例无法按所示工作。类使用与您的用法匹配的筛选器字符串。通常,必须根据数据类型以不同的方式构造筛选器字符串。例如,字符串需要引号(您拥有),但整数值不使用引号。
您拥有的另一个选项是设置具有所需操作的字典。
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));
}
这样做的优点是可以执行更复杂的比较,例如按值范围或包含多个属性的值范围添加自定义筛选器。