创建表达式树以分配给列表的属性
本文关键字:列表 属性 分配 表达式 创建 | 更新日期: 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);
}