views:

99

answers:

1

I understand that Delegates offer high performance reflection maybe just 15% slower than regular explicit c# code. However all the examples I can find on stackoverflow are based on prior knowledge of the type of a method/property being accessed via a delegate.

Given such prior knowledge of a class, why resort to reflected Delegate access in the first place?

Anyhow the reflection coding task I face is how to implement high performance property get/set access for an unknown list of class properties where just a class type name is supplied at runtime? I can code the basics of reflection inspection to produce a list of properties but how do I wire up a set of Delegate based accessors for a potentially random set of property types?

Assuming the property types are limited to a range of basic DB column types is the answer a case statement that returns a:

Func<int> or Func<string> etc? 

Edit-1: I am limited to .Net 3.5

+1  A: 

This solution uses expression trees since they're fairly easy to compose, and they provide the handy Compile() method to get an actual Delegate upon which you can invoke. I made the Func actually take in the object (so Func<T, TResult> rather than just Func<TResult>) so you can obtain the property value from any instance.

Edit: Added setter implementation as well.

public class MyClass
{
    public string MyStringProperty { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        PropertyInfo propertyInfo = typeof(MyClass).GetProperty("MyStringProperty");
        Delegate getter = CreateGetter(propertyInfo);
        Delegate setter = CreateSetter(propertyInfo);
        object myClass = new MyClass();
        setter.DynamicInvoke(myClass, "Hello");
        Console.WriteLine(getter.DynamicInvoke(myClass));
    }

    public static Delegate CreateGetter(PropertyInfo property)
    {
        var objParm = Expression.Parameter(property.DeclaringType, "o");
        Type delegateType = typeof(Func<,>).MakeGenericType(property.DeclaringType, property.PropertyType);
        var lambda = Expression.Lambda(delegateType, Expression.Property(objParm, property.Name), objParm);
        return lambda.Compile();
    }

    public static Delegate CreateSetter(PropertyInfo property)
    {
        var objParm = Expression.Parameter(property.DeclaringType, "o");
        var valueParm = Expression.Parameter(property.PropertyType, "value");
        Type delegateType = typeof(Action<,>).MakeGenericType(property.DeclaringType, property.PropertyType);
        var lambda = Expression.Lambda(delegateType, Expression.Assign(Expression.Property(objParm, property.Name), valueParm), objParm, valueParm);
        return lambda.Compile();
    }
}

Prints out "Hello" by first using the dynamic setter to set it to "Hello" and then using the dynamic getter to obtain the property from the object.

Kirk Woll
@Kirk. Thank you this seems close to what I needed. I should been more clear in the original question, property setting is my main coding task. I can probably take it from Type delegateType = .. MakeGenericType() and then stitch up your code with standard Jon Skeet and Marc Gavell posts on this subject. I assume Lambdas don't play a part in the Delegate property setting scenario?
camelCase
@camelCase, the setter uses expression trees / lambdas as well. See my updated answer.
Kirk Woll
@ Kirk. Thanks for the setter code example. One problem Expression.Assign() is a .Net 4.0 according to the docs, finding the .Net3.5 alternative is something for me to investigate.
camelCase
Expression.Assign is merely a convenience method for, "A BinaryExpression that has the NodeType property equal to Assign and the Left and Right properties set to the specified values." I imagine you should be able to create the BinaryExpression yourself configured in that manner.
Kirk Woll
@Kirk - Can you recommend any resources to learn this from?
James
@James, the nice thing about expression trees is that you're just trying to recreate expressions that you already know how to do natively in C#. I'd recommend just browsing through the `Expression` class and simply try out every single function inside. Once you've got some hands on experience with the API, you'll really feel like you can write any sort of expression at all.
Kirk Woll