To create a delegate from a method you can use the compile type-safe syntax:
private int Method() { ... }
// and create the delegate to Method...
Func<int> d = Method;
A property is a wrapper around a getter and setter method, and I want to create a delegate to a property getter method. Something like
public int Prop { get; set; }
Func<int> d = Prop;
// or...
Func<int> d = Prop_get;
Which doesn't work, unfortunately. I have to create a separate lambda method, which seems unnecessary when the getter method matches the delegate signature anyway:
Func<int> d = () => Prop;
In order to use the delegate method directly, I have to use nasty reflection, which isn't compile type-safe:
// something like this, not tested...
MethodInfo m = GetType().GetProperty("Prop").GetGetMethod();
Func<int> d = (Func<int>)Delegate.CreateDelegate(typeof(Func<int>), m);
Is there any way of creating a delegate on a property getting method directly in a compile-safe way, similar to creating a delegate on a normal method at the top, without needing to use an intermediate lambda method?
The trick is that a
Property
is really just a facade on the actual getter and/or setter methods which are hidden. The compiler emits these method(s) and names them according to the name of theProperty
prepended with get_ and set_, respectively. In the example below it would beint get_Value()
andvoid set_Value(int)
. So just bypass the so-called "property" and just go straight for those methods.With either the getter and/or setter method we have two options.
We can create a bound delegate which has the
this
value for some instance "burned-in." This is similar to what you expect for the property itself, i.e., this delegate will only be good for accessing that one runtime instance. The advantage is that, because the delegate is permanently bound to its instance, you don't have to pass in an extra argument.The other option is to create delegates which aren't associated with a specific target instance. Although these call the exact same property-accessor methods as before, in this case the
Target
property of the delegate itself is empty/null. Lacking anythis
pointer to use, the method signature for an unbound delegate is altered to reveal the famous "hidden this" pointer.Further discussion below, but first here's the code. It illustrates all the four cases, getter/setter -vs- bound/unbound.
n.b., this refers to some helper code that's included at the bottom of this post
To summarize, the "true signature" of the instance method is identical to the bound delegate case, but gets cancelled off. Bound delegates take care of providing it, as the first argument, by supplying the instance they carry around in that
Target
property. Unbound delegates are universal so you never need more than just a single getter/setter pair per-property. They can be used to to access that instance property on any past, present, or future runtime instance, but this means you have to explicitly pass a desired targetthis
object in as the first argument every time you invoke the getter/setter.Note also that even though unbound delegates here are accessing instance properties or methods, you don't actually need any viable runtime instance of
Cls
to create the delegate.Here's a demo.
And the output:
Finally, here's some helper stuff I put down here to reduce clutter. Note that the
MethodInfo
s can be cached and reused if you plan on building lots of bound delegates. If you instead prefer to use the unbound (static) delegates, you won't need to keep them around; because unbound delegates work universally for any instance, so you might decide you never need to create any bound delegates.As far as I can tell, you have already written down all "valid" variants. Since it isn't possible to explicitly address a getter or setter in normal code (without reflection, that is), I don't think that there is a way to do what you want.
Another option (in .NET 3.0 and newer) would be to use a
DependencyProperty
instead of a traditional property. Then you can pass around theDependencyProperty
object (instead of passing around a delegate), and callGetValue()
orSetValue()
when needed.(Yes, I know this is an old question, but it was one of the top posts when I was trying to do something very similar.)