Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a delegate from a property getter or setter method

Tags:

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?

like image 719
thecoop Avatar asked Apr 12 '10 11:04

thecoop


People also ask

What is property getters and setters?

What are Getters and Setters? Getters: These are the methods used in Object-Oriented Programming (OOPS) which helps to access the private attributes from a class. Setters: These are the methods used in OOPS feature which helps to set the value to private attributes in a class.

What are getter and setter methods in C#?

It is a good practice to use the same name for both the property and the private field, but with an uppercase first letter. The get method returns the value of the variable name . The set method assigns a value to the name variable. The value keyword represents the value we assign to the property.


2 Answers

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.

like image 59
Lucero Avatar answered Sep 23 '22 18:09

Lucero


Having spent several hours puzzling this out, here is a solution for when you need to make fast property accessors from another class. Such as if you need to write a cached property map for previously unknown classes that have no klnowledge of that CreateDelegate magic.

A simple innocent data class, such as this one:

public class DataClass {     public int SomeProp { get; set; }     public DataClass(int value) => SomeProp = value; } 

The universal accessor class, where T1 is the type of class that contains a property and T2 is the type of that property looks like this:

public class PropAccessor<T1, T2> {     public readonly Func<T1, T2> Get;     public readonly Action<T1, T2> Set;      public PropAccessor(string propName)     {         Type t = typeof(T1);         MethodInfo getter = t.GetMethod("get_" + propName);         MethodInfo setter = t.GetMethod("set_" + propName);          Get = (Func<T1, T2>)Delegate.CreateDelegate(typeof(Func<T1, T2>), null, getter);         Set = (Action<T1, T2>)Delegate.CreateDelegate(typeof(Action<T1, T2>), null, setter);     } } 

And then you can do:

var data = new DataClass(100);  var accessor = new PropAccessor<DataClass, int>("SomeProp");  log(accessor.Get(data)); accessor.Set(data, 200); log(accessor.Get(data)); 

Basically, you can traverse your classes with reflection at startup and make a cache of PropAccessors for each property, giving you reasonably fast access.

Edit: a few more hours later..

Ended up with something like this. The abstract ancestor to PropAccessor was necessary, so that I could actually declare a field of that type in the Prop class, without resorting to use of dynamic. Ended up approximately 10x faster than with MethodInfo.Invoke for getters and setters.

internal abstract class Accessor {     public abstract void MakeAccessors(PropertyInfo pi);     public abstract object Get(object obj);     public abstract void Set(object obj, object value); }  internal class PropAccessor<T1, T2> : Accessor {     private Func<T1, T2>    _get;     private Action<T1, T2>  _set;      public override object Get(object obj) => _get((T1)obj);     public override void Set(object obj, object value) => _set((T1)obj, (T2)value);      public PropAccessor() { }      public override void MakeAccessors(PropertyInfo pi)     {         _get = (Func<T1, T2>)Delegate.CreateDelegate(typeof(Func<T1, T2>), null, pi.GetMethod);         _set = (Action<T1, T2>)Delegate.CreateDelegate(typeof(Action<T1, T2>), null, pi.SetMethod);     } }  internal class Prop {     public string name;     public int length;     public int offset;     public PropType type;     public Accessor accessor; }  internal class PropMap {     public UInt16 length;     public List<Prop> props;      internal PropMap()     {         length = 0;         props = new List<Prop>();     }      internal Prop Add(PropType propType, UInt16 size, PropertyInfo propInfo)     {         Prop p = new Prop()         {             name   = propInfo.Name,             length = size,             offset = this.length,             type   = propType,             Encode = encoder,             Decode = decoder,         };          Type accessorType = typeof(PropAccessor<,>).MakeGenericType(propInfo.DeclaringType, propInfo.PropertyType);         p.accessor = (Accessor)Activator.CreateInstance(accessorType);         p.accessor.MakeAccessors(propInfo);          this.length += size;         props.Add(p);         return p;     } } 
like image 36
Avo Nappo Avatar answered Sep 21 '22 18:09

Avo Nappo