Как использовать предложение LINQ where для фильтрации коллекции, имеющей динамически генерируемый тип - PullRequest
0 голосов
/ 06 ноября 2011

Мне нужно отфильтровать ObservableCollection с помощью предложения LINQ Where в моем приложении Silverlight.

Тип объекта динамически создается с использованием метода, предоставленного в следующем URL-адресе.http://mironabramson.com/blog/post/2008/06/Create-you-own-new-Type-and-use-it-on-run-time-(C).aspx

Возможно ли отфильтровать мою коллекцию, используя условие Where для конкретного свойства?

Как этого добиться?

Спасибо

Ответы [ 2 ]

0 голосов
/ 26 июля 2017

Поскольку вы знаете тип элемента вашей коллекции только во время выполнения, он, вероятно, равен object во время компиляции. Таким образом, аргумент метода .Where должен быть Func<object, bool>.

Вот фрагмент кода, который создаст такой делегат, которому присвоено свойство фактического типа элемента и лямбда-выражение для свойства (которое, я полагаю, вы знаете тип):

/// <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 }
0 голосов
/ 01 декабря 2011

Единственный способ, которым я знаю, - это использовать отражение, как это:

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