如何使用LINQ where子句过滤具有动态生成类型的集合

时间:2011-11-06 07:35:57

标签: linq silverlight-4.0 linq-to-objects observablecollection dynamic-linq

我需要使用Silverlight应用程序中的LINQ Where子句过滤ObservableCollection。

使用以下url中提供的方法动态创建对象类型。 http://mironabramson.com/blog/post/2008/06/Create-you-own-new-Type-and-use-it-on-run-time-(C).aspx

是否可以使用Where子句过滤我的集合以获取特定属性?

我怎样才能实现它?

由于

2 个答案:

答案 0 :(得分:0)

我知道的唯一方法是使用反射,如下所示:

// using a list of dynamic types
var items = new List<object> { new { A = 0, B = 1 }, new { A = 1, C = 0 } };
// select ao items with A > 0
var filteredItems = items.Where(obj => (int)obj.GetType().GetField("A").GetValue(obj) > 0).ToArray();

// if you have a property instead of field, you should call GetProperty(), like this:
obj.GetType().GetProperty("PropertyName").GetValue(obj, null)

答案 1 :(得分:0)

如果您只在运行时知道集合的元素类型,那么在编译时它可能是object。因此,.Where方法的参数必须是Func<object, bool>

这是一段代码,它将创建这样一个委托给定一个实际元素类型的属性和属性上的lambda表达式(我想你知道它的类型):

/// <summary>
/// Get a predicate for a property on a parent element.
/// </summary>
/// <param name="property">The property of the parent element to get the value for.</param>
/// <param name="propertyPredicate">The predicate on the property value.</param>
static Func<object, bool> GetPredicate<TProperty>(PropertyInfo property, Expression<Func<TProperty, bool>> propertyPredicate)
{
    if (property.PropertyType != typeof(TProperty)) throw new ArgumentException("Bad property type.");

    var pObj = Expression.Parameter(typeof(object), "obj");

    // ((elementType)obj).property;
    var xGetPropertyValue = Expression.Property(Expression.Convert(pObj, property.DeclaringType), property);

    var pProperty = propertyPredicate.Parameters[0];
    // obj => { var pProperty = xGetPropertyValue; return propertyPredicate.Body; };
    var lambda = Expression.Lambda<Func<object, bool>>(Expression.Block(new[] { pProperty }, Expression.Assign(pProperty, xGetPropertyValue), propertyPredicate.Body), pObj);
    return lambda.Compile();
}

样本用法:

var items = new List<object> { new { A = 0, B = "Foo" }, new { A = 1, B = "Bar" }, new { A = 2, B = "FooBar" } };
var elementType = items[0].GetType();

Console.WriteLine("Items where A >= 1:");
foreach (var item in items.Where(GetPredicate<int>(elementType.GetProperty("A"), a => a >= 1)))
    Console.WriteLine(item);

Console.WriteLine();
Console.WriteLine("Items where B starts with \"Foo\":");
foreach (var item in items.Where(GetPredicate<string>(elementType.GetProperty("B"), b => b.StartsWith("Foo"))))
    Console.WriteLine(item);

输出:

Items where A >= 1:
{ A = 1, B = Bar }
{ A = 2, B = FooBar }

Items where B starts with "Foo":
{ A = 0, B = Foo }
{ A = 2, B = FooBar }