2016-07-14 39 views
2
public class Sample 
{ 
public int Id { get; set; } 
public string Description { get; set; } 
public DateTime EffectiveDate { get; set; } 
} 

IEnumberable<Sample> sampleList; 
//Populate the list 
public class Sample 
{ 
public int Id { get; set; } 
public string Description { get; set; } 
public DateTime EffectiveDate { get; set; } 
} 

IEnumberable<Sample> sampleList; 
//Populate the list 

现在我想通过“Id”属性有时候过滤列表,有时候是“Description”属性。只是想将属性名称(filterColumn)和属性值(filterValue)都作为字符串传递。C#Linq筛选器IEnumerable动态属性和值

我试过如下:

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作为 “说明”,但抛出的字符串和INT之间incomptable '=' 操作当“Id”作为filterColumn传递并出现一些filterValue(如“1”)时出错。

感谢任何帮助。谢谢

+0

您的第一个人正在检查它,*属性名称*与指定的属性值相同。您需要在PropertyInfo上调用'.GetValue(x,null)'...然后你想使用'Equals'而不是'=='。 –

+0

你为什么要做'.AsQueryable()'? – Enigmativity

回答

1

你的第一种方法可以工作。扩展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) 
    ); 
} 

IEnumberable<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方法中看到这种类型的过滤器字符串。所以我猜你正在使用一些扩展。您的示例不能如所示。 DataTable类使用与您的使用相匹配的过滤器字符串。通常,必须根据数据类型以不同的方式构造过滤器字符串。例如,一个字符串需要引号(你有),但整数值不使用引号。

1

您拥有的另一个选择是使用所需的操作设置字典。

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

这里的优点是,可以执行更复杂的比较,例如,通过值的范围,或那些含有一个以上的属性添加自定义过滤器。