Dynamically use LINQ aggregator

Asked

Viewed 140 times

6

I am trying to create a function to use Linq aggregator functions (sum, Average, Count) and I am not succeeding. I have the following code:

    private double AgreggateDynamic<T>(IEnumerable<T> list, string propertyName, string func)
    {            
        //Converter o "array" para uma lista não resolveu
        //IEnumerable<T> listEnum = list.ToList();
        Type enumerableType = typeof(Enumerable);

        MethodInfo sumMethod = typeof(Enumerable).GetMethods().First(
            m => m.Name == func
                && m.IsGenericMethod);

        MethodInfo generic = sumMethod.MakeGenericMethod(enumerableType);

        Func<T, double> expression = x => Convert.ToDouble(x.GetType().GetProperty(propertyName).GetValue(x, null));            
        object[] parametersArray = new object[] { list, expression };

        return Convert.ToDouble(generic.Invoke(null, parametersArray));
    }

    AgreggateDynamic(list, "FooValue", "Sum");

When I run this code snippet, the line return Convert.ToDouble(generic.Invoke(null, parametersArray));, I have the following error.

The type object 'Manager.Business.Tests.Foo[]' cannot be converted to type 'System.Collections.Generic.Ienumerable`1[System.Linq.Enumerable]'.

Any idea what I can do?

  • By the error message, the problem is that you are sending an array as a parameter, rather than implementing the Ienumerable interface (a list for example). Try to change this array to a list and check if the error remains.

  • I’ve tried that. Something like Ienumerable<T> listEnum = list.Tolist();, and returns the same error.

  • I don’t understand what the idea is of doing this.

  • Well, the idea is to be able to configure in a database some queries that will be transformed into graphs, dynamically, of data sources that I don’t have models (procedures, webapi). And I define in everything that is necessary to do group bys, aggregations and others. In this case, I am generating a dynamic aggregation to generate a query.

  • Do you need all this? I’d make it simpler.

  • Yes, I do, unfortunately.

  • I need an example of list to ride a Fiddle for you.

  • Have you tried the .ToEnumerable(); ?

Show 3 more comments

1 answer

4


See if this solution meets your need:

public static double AgreggateDynamic<T>(IEnumerable<T> list, string propertyName, string func)
{
    Func<T, double> expression = x => Convert.ToDouble(x.GetType().GetProperty(propertyName).GetValue(x, null));

    switch (func.ToLower())
    {
        case "sum": return list.Sum(expression);
        case "average": return list.Average(expression);
        case "count": return list.Count();
        default:
            return 0;
    }
}


static void Main(string[] args)
{
    var list = new []
    {
        new { FooValue = 512313, FooValue2 = 5123 },
        new { FooValue = 512313, FooValue2 = 5123 },
        new { FooValue = 512313, FooValue2 = 5123 },
        new { FooValue = 512313, FooValue2 = 5123 },
    };

    Console.WriteLine("Sum: " + AgreggateDynamic(list, "FooValue", "Sum"));
    Console.WriteLine("Average: " + AgreggateDynamic(list, "FooValue", "Average"));
    Console.WriteLine("Count: " + AgreggateDynamic(list, "FooValue", "Count"));
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.