如何编写用于在 SelectMany 中进行选择的表达式树?
How to write an expression tree for selecting inside of SelectMany?
考虑以下 Person
class
// 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>(IEnumerable<TSource> source, Func<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<,>).MakeGenericType(args[0], 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
.
中
考虑以下 Person
class
// 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>(IEnumerable<TSource> source, Func<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<,>).MakeGenericType(args[0], 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
.