创建表达式树以分配给列表的属性

本文关键字:列表 属性 分配 表达式 创建 | 更新日期: 2023-09-27 18:29:22

这已经困扰我好几天了。。。。

如果我有一个自己的对象SearchResults的列表,并且SearchResults包含多个对象列表,所有这些对象都具有match(bool)属性,我如何重新创建表达式树以实现以下目标:

//searchResults is a List<SearchResults>
searchResults[i].Comments = searchResults[i].Comments.Select(p1 =>
{
    p1.Match = ListOfStringVariable.All(p2 =>
    {
        string value = (string)typeof(CommentData).GetProperty(propertyName).GetValue(p1);
        return value.Contains(p2);
    });
    return p1;
}).OrderByDescending(x => x.Match);
....
public class SearchResults
{
    public IEnumerable<CommentData> Comments { get; set; }
    public IEnumerable<AdvisorData> Advisors { get; set; }
}
public class CommentData
{
    public string CommentText { get; set; }
    public bool Match { get; set; }
}
public class AdvisorData
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public bool Match { get; set; }
}

表达式树是必要的,因为我不知道在编译时需要分配的属性,无论是Comments、Advisors等(因为这是一个更大问题的简化)。上面的例子只是针对Comments,那么在没有条件块的情况下,如何使用相同的代码来分配给Advisors呢?

非常感谢

更新:

到目前为止,使用反射,我们有来自StriplingWarrior 的以下内容

var searchResult = searchResults[i];
foreach (var srProperty in searchResultsProperties)
{
    var collectionType = srProperty.PropertyType;
    if(!collectionType.IsGenericType || collectionType.GetGenericTypeDefinition() != typeof(IEnumerable<>))
    {
        throw new InvalidOperationException("All SearchResults properties should be IEnumerable<Something>");
    }
    var itemType = collectionType.GetGenericArguments()[0];
    var itemProperties = itemType.GetProperties().Where(p => p.Name != "Match");
    var items = ((IEnumerable<IHaveMatchProperty>) srProperty.GetValue(searchResult))
        // Materialize the enumerable, in case it's backed by something that
        // would re-create objects each time it's iterated over.
        .ToList();
    foreach (var item in items)
    {
        var propertyValues = itemProperties.Select(p => (string)p.GetValue(item));
        item.Match = propertyValues.Any(v => searchTerms.Any(v.Contains));
    }
    var orderedItems = items.OrderBy(i => i.Match);
    srProperty.SetValue(srProperty, orderedItems);
}

然而,orderedItems属于System.Linq.OrderedEnumerable<IHaveMatchProperty,bool>类型,并且需要转换为IEnumerable<AdvisorData>。以下抛出错误:

"System.Linq.Enumerable.CastIterator(System.Collections.IEnumerable)"是一个"方法",但使用方式类似于"类型"

var castMethod = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(new[] {propertyType});
var result = castMethod.Invoke(null, new[] { orderedItems });

其中propertyType是类型AdvisorData

创建表达式树以分配给列表的属性

首先,让您的类型实现这个接口,这样您就不必进行太多的反射:

public interface IHaveMatchProperty
{
    bool Match { get; set; }
}

然后编写代码来执行类似的操作。(我做了很多假设,因为你的问题对你的预期行为不是很清楚。)

var searchResult = searchResults[i];
foreach (var srProperty in searchResultsProperties)
{
    var collectionType = srProperty.PropertyType;
    if(!collectionType.IsGenericType || collectionType.GetGenericTypeDefinition() != typeof(IEnumerable<>))
    {
        throw new InvalidOperationException("All SearchResults properties should be IEnumerable<Something>");
    }
    var itemType = collectionType.GetGenericArguments()[0];
    var itemProperties = itemType.GetProperties().Where(p => p.Name != "Match");
    var items = ((IEnumerable<IHaveMatchProperty>) srProperty.GetValue(searchResult))
        // Materialize the enumerable, in case it's backed by something that
        // would re-create objects each time it's iterated over.
        .ToList();
    foreach (var item in items)
    {
        var propertyValues = itemProperties.Select(p => (string)p.GetValue(item));
        item.Match = propertyValues.Any(v => searchTerms.Any(v.Contains));
    }
    var orderedItems = items.OrderBy(i => i.Match);
    srProperty.SetValue(srProperty, orderedItems);
}