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?