【问题标题】:How to use LINQ where clause for filtering the collection having dynamically generated type如何使用 LINQ where 子句过滤具有动态生成类型的集合
【发布时间】:2011-11-06 07:35:56
【问题描述】:

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

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

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

我怎样才能实现它?

谢谢

【问题讨论】:

  • 您可以编辑您的帖子并显示填充集合的代码吗?
  • Q1:集合中的所有元素都是同一个(动态创建的)类型吗?
  • Q2:过滤器到底是什么样的?将属性值与常量值进行比较?请举一些例子

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


【解决方案1】:

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

// 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)

【讨论】:

  • 对每一项都进行反思不是很有效。将使用表达式发布答案以获得编译的谓词。
【解决方案2】:

您只在运行时知道集合的元素类型,它在编译时可能是object。所以.Where 方法的参数必须是Func&lt;object, bool&gt;

这是一段代码,它将创建这样一个委托,给定实际元素类型的属性和属性上的 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 }

【讨论】:

  • 您的代码没有涵盖并非列表中的所有项目都由相同的匿名类型表示的情况。
猜你喜欢
  • 2011-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-01
  • 2015-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多