2

I've a method on a generic base class that I want to execute for all superclasses of it

The logic is something like:

BuildAverageDateStats(List<type> items, DateProperty1 exp, DateProperty2 exp2)
{
 return new Stat{ 
  Value = items.Average(c => (c.DateProperty2 - c.DateProperty1).Milliseconds)
 };
}

myobject.BuildAverageDateStats(list, () => c.QueuedDate, () => c.CompletedDate);
myobject.BuildAverageDateStats(list, () => c.ActionedDate, () => c.CompletedDate);

I think I need expressions, but not sure how...

I could send it in as Func i.e. Value = items.Average(c => myfunc(c)) but looking for a property substitution example.

jenson-button-event
  • 18,101
  • 11
  • 89
  • 155
  • I'm thinking Expressions if you want to try to pass in properties (statically) and get their values. It is both more performance and more type-safe than reflections. But I'm a bit confused as to what you're trying to accomplish. Will the same properties exist on all derived classes, or will they be different properties each time? And if they're different each time, I'm a bit confused as to how you will be accomplishing DRY with your proposed syntax. Don't you have to pass in the different properties for each type anyhow? – Merlyn Morgan-Graham Sep 30 '11 at 11:15
  • DRY was probably an exageration. We will always be comparing 2 date properties, just not sure which properties and which order (we've 3 possible date properties on the type and type is always the same). Func is fine and its what I'm using, I guess I'm looking to understand how to achieve property substitution – jenson-button-event Sep 30 '11 at 12:38
  • I'd investigate if it makes sense for your final solution to be an extension method on `IEnumerable`. Basing it off an instance of `type` seems strange. – Merlyn Morgan-Graham Sep 30 '11 at 20:20

3 Answers3

2
Stat BuildAverageDateStats<U>(List<type> items, Func<U, double> exp)
where U:type
{
 return new Stat{ 
  Value = items.OfType<U>().Average(exp);
 };
}

You can call it like this

BuidlAverageDateStats<Dog>(items, d=>d.Age - d.Height);

Though my example doesn't make sense.

Muhammad Hasan Khan
  • 34,648
  • 16
  • 88
  • 131
0

If you are really only ever going to use one of the three DateTime properties that you have right now, I would keep the method signature the way you have it right now. To make things neater, make some public static readonly delegate fields on your class for your properties, and use those, instead of writing the same expression time and time again:

    public static readonly DateSelector Date1Property = delegate(CompareTest c) { return c.Date1; };
    public static readonly DateSelector Date2Property = delegate(CompareTest c) { return c.Date2; };
    public static readonly DateSelector Date3Property = delegate(CompareTest c) { return c.Date3; };

If, on the other hand, you expect inheriting classes to implement more properties than the three you have right now, you could consider passing in the properties as String and using the Dynamic Linq Library (and build a dynamic expression that returns the property) or a DynamicMethod to return your property. Both would have the benefits of reflection with the painful performance. If you need it, I have some code laying around for that. Type safety will be out the window though, so I wouldn't use it unless necessary, and it sounds like it isn't.

Menno

Menno van den Heuvel
  • 1,851
  • 13
  • 24
0
static Stat BuildAverageDateStats<T>(List<T> items, string pname1, string pname2){
    return new Stat { 
        Value = items.Average( c => 
        {
            var ty = c.GetType();
            var pv1 = (dynamic)ty.GetProperty(pname1).GetValue(c,null);
            var pv2 = (dynamic)ty.GetProperty(pname2).GetValue(c,null);
            return pv2 - pv1;
        })
    };
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70