如何解决如何编写用于在 SelectMany 内部进行选择的表达式树?
考虑以下 Person
类
// Person.cs
public class Person
{
public Guid Id { get; set; }
public string Name { get; set; }
public string FamilyName { get; set; }
public float Age { get; set; }
public DateTimeOffset BithDate { get; set; }
public IEnumerable<Address> Addresses { get; set; }
public Person()
{
Addresses = new List<Address>();
}
}
// Address.cs
public class Address
{
public string Country { get; set; }
public string City { get; set; }
public string MainStreet { get; set; }
public string Info { get; set; }
public string No { get; set; }
}
var list = PeopleDataGenerator.GetPeople()
.SelectMany(x => x.Addresses)
.Select(x => x.City)
;
如何使用表达式树完成这部分.SelectMany(x => x.Addresses) .Select(x => x.City)
?
解决方法
不清楚您是要IEnumerable
还是IQueryable
...对于IEnumerable
:
给定:
/// <summary>
/// IEnumerable<TResult> Enumerable.SelectMany<TSource,TResult>(IEnumerable<TSource> source,Func<TSource,IEnumerable<TResult>> selector)
/// </summary>
public static readonly MethodInfo SelectMany1 = (from x in typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
where x.Name == nameof(Enumerable.SelectMany)
let args = x.GetGenericArguments()
where args.Length == 2
let pars = x.GetParameters()
where pars.Length == 2 &&
pars[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(args[0]) &&
pars[1].ParameterType == typeof(Func<,>).MakeGenericType(args[0],typeof(IEnumerable<>).MakeGenericType(args[1]))
select x).Single();
/// <summary>
/// IEnumerable<TResult> Enumerable.Select<TSource,TResult> selector)
/// </summary>
public static readonly MethodInfo Select1 = (from x in typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
where x.Name == nameof(Enumerable.Select)
let args = x.GetGenericArguments()
where args.Length == 2
let pars = x.GetParameters()
where pars.Length == 2 &&
pars[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(args[0]) &&
pars[1].ParameterType == typeof(Func<,args[1])
select x).Single();
(我有一个完整的 gist 定义)
你可以
// SelectMany
var par1 = Expression.Parameter(typeof(Person));
var sub1 = Expression.Property(par1,nameof(Person.Addresses));
var lambda1 = Expression.Lambda<Func<Person,IEnumerable<Address>>>(sub1,par1);
var selectMany = Expression.Call(SelectMany1.MakeGenericMethod(typeof(Person),typeof(Address)),par0,lambda1);
// Select
var par2 = Expression.Parameter(typeof(Address));
var sub2 = Expression.Property(par2,nameof(Address.City));
var lambda2 = Expression.Lambda<Func<Address,string>>(sub2,par2);
var select = Expression.Call(Select1.MakeGenericMethod(typeof(Address),typeof(string)),selectMany,lambda2);
// persons => Select(SelectMany(persons))
var par0 = Expression.Parameter(typeof(IEnumerable<>).MakeGenericType(typeof(Person)));
var lambda0 = Expression.Lambda<Func<IEnumerable<Person>,IEnumerable<string>>>(select,par0);
var compiled = lambda0.Compile();
如果您想要 SelectMany+Select
调用,它位于 select
变量中。如果您想要使用 SelectMany+Select
的可编译表达式,则它位于 lambda0
和 compiled
中。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。