0

I am trying to create a way to run some dynamic linq on a data table, the code I have pasted is test code not my full code that I am working on, but I think it is enough to get across what I am attempting to do.

Essentially I want to add a second parameter to the the method that will contain an expression that can be used to replace the r => r.Field("field").

public string GetStringValueFromData(DataTable data)
{
    switch (this.MethodType)
    {
        case (LabelMethodType.Count):
            return data.AsEnumerable().Select(r => r.Field<string>("sometextfield")).Count().ToString();
        case (LabelMethodType.Sum):
            return data.AsEnumerable().Sum(r => r.Field<decimal>("somenumberfield")).ToString();
        case (LabelMethodType.Average):
            return data.AsEnumerable().Average(r => r.Field<decimal>("anotherfield")).ToString();
    }

    return string.Empty;
}

so essentially the method would look something like this. But of course I have tried this and it does not even compile.

public string GetStringValueFromData(DataTable data, Expression<Func<DataRow, object>> expression)
{
    switch (this.MethodType)
    {
        case (LabelMethodType.Count):
            return data.AsEnumerable().Select(expression).Count().ToString();
        case (LabelMethodType.Sum):
            return data.AsEnumerable().Sum(expression).ToString();
        case (LabelMethodType.Average):
            return data.AsEnumerable().Average(expression).ToString();
    }

    return string.Empty;
}

Does anyone possibly know what type could make the parameter for this to work, so that it will accept something like r => r.Field("sometextfield") or r => r.Field("somenumberfield") or have suggestions of an alternative approach.

Thanks

CD

Chris Schiffhauer
  • 17,102
  • 15
  • 79
  • 88
  • 2
    Well, the first thing is that, since you're dealing with LINQ to objects, and not an `IQueryable`, you'll want to just pass in a `Func`, not an `Expression`. However that's not the only change you'll need to make. – Servy Feb 06 '14 at 16:47

1 Answers1

0

This should work as expected:

public string GetStringValueFromData(DataTable data, Func<DataRow, object> expression)
{
    switch (this.MethodType)
    {
        case (LabelMethodType.Count):
            return data.AsEnumerable().Select(expression).Count().ToString();
        case (LabelMethodType.Sum):
            return data.AsEnumerable().Select(expression).Cast<int>().Sum().ToString();
        case (LabelMethodType.Average):
            return data.AsEnumerable().Select(expression).Cast<int>().Average().ToString();
    }

    return string.Empty;
}

Notes:

You don't need to use Expression< Func<> >, you can use just Func<>.

The Select expression for the Count case is not necessary, the projection will never affect the count.

thepirat000
  • 12,362
  • 4
  • 46
  • 72
  • yeah that seems to work, I had taken off the Expression part and turned to just a Func<> based on what Servy suggested, the only question I need to sort out now is choosing the correct Cast<> but this has got me past the main blockage, thanks for the help. – Mr Cecil Dooberry Feb 06 '14 at 17:08
  • The projections aren't always projecting out to integers. They aren't projecting out to any constant numeric type, so this solution won't do what is requested of it. – Servy Feb 06 '14 at 17:42