Reputation: 481
Let me re-post my question.
Here is my static class to wrap some call to Async
public static class QueryExtensions
{
internal static async Task<List<TSource>> ToListAsync<TSource>(this IQueryable<TSource> query)
{
//Initialzie
var call = Expression.Call(typeof(Enumerable), nameof(Enumerable.ToList), new Type[] { typeof(T) }, query.Expression);
//Execute
return await ExecuteAsync<List<TSource>>(call);
}
public static async Task<Dictionary<TKey, TSource>> ToDictionaryAsyn<TKey, TSource>(this IQueryable<TSource> query, Func<TSource, TKey> keySelector)
{
//I don't know how to pass keySelector to following
var call = Expression.Call(typeof(Enumerable), nameof(Enumerable.ToDictionary), new Type[] { typeof(TKey), typeof(TSource) }, query.Expression);
//Execute
return await ExecuteAsync<Dictionary<TKey, TSource>>(call);
}
private static Task<TResult> ExecuteAsync<TResult>(MethodCallExpression expression)
{
//Do some in Asyn
}
}
I will call it in following code
await list.AsQueryable().ToListAsync(); -- It work now
await list.AsQueryable().ToDictionaryAsyn(current => current.Name);
I don't know how to implement ToDictionaryAsyn method
Upvotes: 0
Views: 345
Reputation:
An example as below. Hope it helps.
public static class Extns
{
public static Dictionary<TKey, TSource> ToDictWithSelector<TKey, TSource>(this IQueryable<TSource> query,
Expression<Func<TSource, TKey>> keySelector)
{
var p = Expression.Parameter(typeof(IQueryable<TSource>));
var call = Expression.Call(typeof(Enumerable),
nameof(Enumerable.ToDictionary),
new[] { typeof(TSource), typeof(TKey) },
new Expression[] { p, keySelector });
var lambda = Expression.Lambda<Func<IQueryable<TSource>, Dictionary<TKey, TSource>>>(call, p);
Func<IQueryable<TSource>, Dictionary<TKey, TSource>> func = lambda.Compile();
return func(query.AsQueryable());
}
}
// usage of the above extension
static void Main(string[] args)
{
var list = new List<People>();
list.Add(new People() { Name = "Eagle", Age = 18 });
list.Add(new People() { Name = "Sam", Age = 30 });
list.Add(new People() { Name = "May", Age = 24 });
Expression<Func<People, string>> selector = p => p.Name;
Dictionary<string, People> rr1 = list.AsQueryable().ToDictWithSelector(selector);
Expression<Func<People, int>> selector2 = p => p.Age;
Dictionary<int, People> rr2 = list.AsQueryable().ToDictWithSelector(selector2);
}
Upvotes: 0
Reputation: 142943
If your goal is to generate something like (List<People> l) => l.ToDictionary(p => p.Name)
you can achieve it like this:
// declare parameter of type IEnumerable<People>
var p = Expression.Parameter(typeof(IEnumerable<People>));
// find Enumerable.ToDictionary(this list, keySelector)
var method = typeof(Enumerable)
.GetMethods()
.Where(mi => mi.Name == nameof(Enumerable.ToDictionary) && mi.GetParameters().Length == 2)
.Single();
// apply generic parameters
var concreteMethod = method.MakeGenericMethod(new[] {typeof(People), typeof(string)});
// create selector
Expression<Func<People, string>> selector = p => p.Name;
var call = Expression.Call(null, concreteMethod, p, selector);
// create lambda
var lambda = Expression.Lambda<Func<List<People>, Dictionary<string,People>>>(call, p);
var func = lambda.Compile();
var result = func(list);
Upvotes: 1