views:

58

answers:

1

I'm trying to write a helper class that represents fields on an object. The helper class needs to be able to both get the value of the field on a given instance AND return metadata about the underlying property that it can obtain by reflection.

I'd like the helper class be created by a utility method that gets called something like the following:

public IEnumerable<IFieldInfo<SomeType>> Fields {
  get {
    yield return FieldHelper.GetFieldInfo<SomeType>(t => t.SomeField);
    yield return FieldHelper.GetFieldInfo<SomeType>(t => t.SomeOtherField);
  }
}

Say that the IFieldInfo interface looks a bit like this:

interface IFieldInfo<in T> {
  public string PropertyName {get;}
  public object GetValue(T obj);
}

In the context of my application, the Fields property will be accessed fairly often; the GetValue() method will be called fairly often, but the PropertyName (and the other metadata/reflectiony fields that I omitted for clarity) will be accessed less frequently. There are a lot of places where the Fields property needs to be implemented, and sometimes a lot of fields, so it's important for code clarity and maintenance that the code that calls GetFieldInfo be simple and clear; duplicating the list of fields or duplicating the parameter would be just asking for bugs where they get out of sync.

So, how do I write GetFieldInfo? If I do:

public static IFieldInfo<T> GetFieldInfo<T>(Func<T, object> getter);

then I can implement GetValue() trivially by calling getter(obj) but I have no way to access the name.

If, on the other hand, I do:

public static IFieldInfo<T> GetFieldInfo<T>(Expression<Func<T, object>> getter)

then I can extract the name of the property access that's represented by the expression, but the only way to implement GetValue() is to call Compile() on the expression, which I imagine to be a ridiculous amount of overhead for something that the compiler itself could compile for me, especially since GetValue() is used more often on these objects than PropertyName is.

Is there any way to write my GetFieldInfo helper function to take a single parameter and interpret it as both an expression tree AND a delegate without the overhead of compiling the expression tree into a delegate at runtime?

+1  A: 

I can't see any way that would be possible. The delegate and the Expression are two different object type, which just happen to look alike. It would be akin to writing:

  MyFunc("10m");

And having the paramter treated as both a string and as a decimal without doing any conversion.

Your best bet would be to call Compile() and caching the result. I assume you were already planning on caching the result of searching through the Expression for the property Name.

James Curran
yes, but if you wrote MyFunc(10) it's trivial (resourcewise) to call ToString() on the argument and get it in the other form. If Expression.Compile() were similarly trivial, or there were some way to declare "I am sure that I will want the compiled version of this so cache it for me in advance to make my Compile() method superfast" I'd be quite happy to just take Expression as the parameter.
Stuart
As far as caching the result of the call to Compile - yes, that helps somewhat, except that the Fields property itself is called more often than GetValue is - which is to say, the GetFieldInfo() method often would end up getting called without its result getting used in any way.
Stuart
@Stuart: The point isn't whether or not ToString() is trivial --- The point is whether or not it *must be done*. (It must be)
James Curran