Reputation: 3076
I need to write a generic method for getting distinct values and propertyName is not known in advance. I want to do it using the LINQ expression. I am trying the below way but when getting the result from SelectMethod invoke I am getting WhereSelectListIterator. I want to convert it to IEnumerable so I can call the Distinct method. But I am not to cast it to IEnumerable(as it's not implemented it). How to get Enumerable back from WhereSelectListIterator or is there any way I can get IEnumerable directly from invoke of generic method.
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; using System.Threading.Tasks;
namespace ConsoleApp10 {
public class EmployeeEqualityComparer : IEqualityComparer<Employee>
{
public bool Equals(Employee x, Employee y)
{
return x.Id == y.Id;
}
public int GetHashCode(Employee obj)
{
return obj.Id;
}
}
class Program
{
static void Main(string[] args)
{
var employees = new List<Employee>()
{ new Employee(){Id=1},
new Employee(){Id=2},
new Employee(){Id=1}};
var values1 = employees.Select(obj => obj.Id).Distinct();
var values2 = employees.Distinct(new EmployeeEqualityComparer());
var values= GetDistinctValue(employees, "Id");
}
private static readonly MethodInfo DistinctMethod = typeof(Enumerable).GetMethods().First(method =>
method.Name == "Distinct" &&
method.GetParameters().Length == 1);
private static readonly MethodInfo SelectMethod = typeof(Enumerable).GetMethods().First(method =>
method.Name == "Select" && method.GetParameters().Length == 2);
public static IEnumerable<object> GetDistinctValue<T>(IEnumerable<T> records, string propertyName)
{
try
{
ParameterExpression parameterExpression = Expression.Parameter(typeof(T));
Expression propertyExpression = Expression.Property(parameterExpression, propertyName);
var lambda = Expression.Lambda(propertyExpression, parameterExpression);
var propertyType = propertyExpression.Type;
// MethodCallExpression compareCall = Expression.Call(typeof(Program), "Compare", Type.EmptyTypes, propertyExpression, Expression.Constant(""), Expression.Constant(""), Expression.Constant(""));
//LambdaExpression lambda = Expression.Lambda<Func<T, bool>>(compareCall, parameterExpression);
MethodInfo genericMethod = SelectMethod.MakeGenericMethod(typeof(T),propertyType);
var result = genericMethod.Invoke(null, new object[] { records, lambda.Compile() });
MethodInfo distinctGenericMethod = DistinctMethod.MakeGenericMethod(result.GetType());
var finalResult = distinctGenericMethod.Invoke(null, new object[] { result});
return null;
}
catch(Exception exception)
{
Console.WriteLine(exception.Message);
}
return null;
}
}
public class Employee
{
public int Age { get; set; }
public string Name { get; set; }
public int Id { get; set; }
}
}
Upvotes: 0
Views: 775
Reputation: 27461
This is working version of GetDistinctValue
. Main idea that you can work with IEnumerable
via IQueryable
which is dynamic by default.
public static IEnumerable<object> GetDistinctValue<T>(IEnumerable<T> records, string propertyName)
{
var parameterExpression = Expression.Parameter(typeof(T), "e");
var body = (Expression)Expression.Property(parameterExpression, propertyName);
if (body.Type != typeof(object))
{
body = Expression.Convert(body, typeof(object));
}
var lambda = Expression.Lambda(body, parameterExpression);
// turn IEnumerable into IQueryable
var queryable = records.AsQueryable();
var queryExpression = queryable.Expression;
// records.Select(e => (object)e.propertyName)
queryExpression = Expression.Call(typeof(Queryable), nameof(Queryable.Select),
new[] { typeof(T), typeof(object) }, queryExpression, lambda);
// records.Select(e => (object)e.propertyName).Distinct()
queryExpression = Expression.Call(typeof(Queryable), nameof(Queryable.Distinct), new[] { typeof(object) },
queryExpression);
// creating IQueryable<object> from generated expression
var resultQuery = queryable.Provider.CreateQuery<object>(queryExpression);
// turn IQueryable into IEnumerable
return resultQuery.AsEnumerable();
}
Upvotes: 0