tags:

views:

1151

answers:

3

Given the following class:

class TestClass {
  public void SetValue(int value) { Value = value; }
  public int Value { get; set; }
}

I can do

TestClass tc = new TestClass();
Action<int> setAction = tc.SetValue;
setAction.Invoke(12);

which is all good. Is it possible to do the same thing using the property instead of the method? Preferably with something built in to .net.

+1  A: 

Properties are really wrappers around methods in .Net, so using reflection you should be able to get the delegate (set_PROPERTY and get_PROPERTY) and then execute them...

See System.Reflection.PropertyInfo

If has two methods which you can use to get/ set the value - GetGetMethod and GetSetMethod.

So you could write:

var propertyInfo = typeof (TestClass).GetProperty ("Value");

var setMethod = property.GetSetMethod (); // This will return a MethodInfo class.
Kieron
Even though the C# specification reserves methods get_P and set_P for any property P, it does not require implementations to use these methods for properties. This makes it an implementation detail. Do not rely on undocumented implementation details.
DrJokepu
By using the PropertyInfo class and the GetGet/SetMethod it's no longer an implementation problem. It's part of the framework at that point.
Kieron
Kieron: Fair enough.
DrJokepu
+4  A: 

There are three ways of doing this; the first is to use GetGetMethod()/GetSetMethod() and create a delegate with Delegate.CreateDelegate. The second is a lambda (not much use for reflection!) [i.e. x=>x.Foo]. The third is via Expression (.NET 3.5).

The lambda is the easiest ;-p

    class TestClass
    {
        public int Value { get; set; }
    }
    static void Main()
    {
        Func<TestClass, int> lambdaGet = x => x.Value;
        Action<TestClass, int> lambdaSet = (x, val) => x.Value = val;

        var prop = typeof(TestClass).GetProperty("Value");
        Func<TestClass, int> reflGet = (Func<TestClass, int>) Delegate.CreateDelegate(
            typeof(Func<TestClass, int>), prop.GetGetMethod());
        Action<TestClass, int> reflSet = (Action<TestClass, int>)Delegate.CreateDelegate(
            typeof(Action<TestClass, int>), prop.GetSetMethod());
    }

To show usage:

        TestClass foo = new TestClass();
        foo.Value = 1;
        Console.WriteLine("Via property: " + foo.Value);

        lambdaSet(foo, 2);
        Console.WriteLine("Via lambda: " + lambdaGet(foo));

        reflSet(foo, 3);
        Console.WriteLine("Via CreateDelegate: " + reflGet(foo));

Note that if you want the delegate pointing to the specific instance, you can use closures for the lambda, or the overload of CreateDelegate that accepts and instance.

Marc Gravell
Would you mind posting examples?
Filip
btw, I haven't posted an Expression example, as it tends to be verbose. However, some Expression posts are on my blog: http://marcgravell.blogspot.com/search/label/expression
Marc Gravell
+9  A: 

You could create the delegate using reflection :

Action<int> valueSetter = (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), tc, tc.GetType().GetProperty("Value").GetSetMethod());

or create a delegate to an anonymous method which sets the property;

Action<int> valueSetter = v => tc.Value = v;

Edit: used wrong overload for CreateDelegate(), need to use the one that takes and object as target. Fixed.

Pop Catalin
I think this will work for the needs I have. Thanks!
Robert Höglund
Given that C# is supposed to be my first language I really wish I'd understand this stuff (creating a delegate using reflection) - sounds great
JohnIdol
And for .net 2.0 one could do Action<int> valueSetter = delegate(int value) { tc.Value = value; }
Robert Höglund
@Robert, you can target .Net 2.0 using the C# 3.0 compiler, there's no reason to stick to the C# 2.0 compiler ;)
Pop Catalin
FWIW, I was curious, and benchmarked your two approaches given above (except since I'm targeting .Net 2.0, I used Action<int> valueSetter = delegate(int v) { tc.Value = v; }; instead of the lambda you gave). The tradeoff you get for compile-time type- and name-checking (the anonymous delegate / lambda version) is that it takes twice as long, because the code calls a delegate which calls the property setter. The first approach directly calls the property setter, so while you don't get compile-time checking, you get twice the speed, which for my particular approach is significant.
Dathan