0

I need to filter the ObservableCollection using LINQ Where clause in my Silverlight application.

The object type is dynamically created using method provided in following url. http://mironabramson.com/blog/post/2008/06/Create-you-own-new-Type-and-use-it-on-run-time-(C).aspx

Is filtering my collection using Where clause for specific property possible?

How can I achieve it?

Thanks

HBA
  • 1

2 Answers2

0

As you know the element type of your collection only at run time it probably is object at compile time. So the argument to the .Where method has to be a Func<object, bool>.

Here's a piece of code that will create such a delegate given a property of the actual element type and a lambda expression on the property (which i suppose you know the type of):

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

Sample usage:

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

Output:

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 }
tinudu
  • 1,139
  • 1
  • 10
  • 20
0

The only way I know is using reflection, like this:

// 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)
Marcelo De Zen
  • 9,439
  • 3
  • 37
  • 50
  • Not very efficient to reflect on every item. Will post an answer using expressions to get a compiled predicate. – tinudu Jul 26 '17 at 09:19