I am trying to create a delegate (as a test) for:
Public Overridable ReadOnly Property PropertyName() As String
My intuitive attempt was declaring the delegate like this:
Public Delegate Function Test() As String
And instantiating like this:
Dim t As Test = AddressOf e.PropertyName
But this throws the error:
Method 'Public Overridable ReadOnly Property PropertyName() As String' does not have a signature compatible with delegate 'Delegate Function Test() As String'.
So because I was dealing with a property I tried this:
Public Delegate Property Test() As String
But this throws a compiler error.
So the question is, how do I make a delegate for a property?
See this link:
http://peisker.net/dotnet/propertydelegates.htm
Re the problem using AddressOf - if you know the prop-name at compile time, you can (in C#, at least) use an anon-method / lambda:
Test t = delegate { return e.PropertyName; }; // C# 2.0 Test t = () => e.PropertyName; // C# 3.0
I'm not a VB expert, but reflector claims this is the same as:
Dim t As Test = Function Return e.PropertyName End Function
Does that work?
Original answer:
You create delegates for properties with Delegate.CreateDelegate
; this can be open for any instance of the type, of fixed for a single instance - and can be for getter or setter; I'll give an example in C#...
using System; using System.Reflection; class Foo { public string Bar { get; set; } } class Program { static void Main() { PropertyInfo prop = typeof(Foo).GetProperty("Bar"); Foo foo = new Foo(); // create an open "getter" delegate Func<Foo, string> getForAnyFoo = (Func<Foo, string>) Delegate.CreateDelegate(typeof(Func<Foo, string>), null, prop.GetGetMethod()); Func<string> getForFixedFoo = (Func<string>) Delegate.CreateDelegate(typeof(Func<string>), foo, prop.GetGetMethod()); Action<Foo,string> setForAnyFoo = (Action<Foo,string>) Delegate.CreateDelegate(typeof(Action<Foo, string>), null, prop.GetSetMethod()); Action<string> setForFixedFoo = (Action<string>) Delegate.CreateDelegate(typeof(Action<string>), foo, prop.GetSetMethod()); setForAnyFoo(foo, "abc"); Console.WriteLine(getForAnyFoo(foo)); setForFixedFoo("def"); Console.WriteLine(getForFixedFoo()); } }
I just create an helper with pretty good performance : http://thibaud60.blogspot.com/2010/10/fast-property-accessor-without-dynamic.html It don't use IL / Emit approach and it is very fast !
Edit by oscilatingcretin 2015/10/23
The source contains some casing issues and peculiar =""
that have to be removed. Before link rot sets in, I thought I'd post a cleaned-up version of the source for easy copy pasta, as well as an example of how to use it.
Revised source
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; namespace Tools.Reflection { public interface IPropertyAccessor { PropertyInfo PropertyInfo { get; } object GetValue(object source); void SetValue(object source, object value); } public static class PropertyInfoHelper { private static ConcurrentDictionary<PropertyInfo, IPropertyAccessor> _cache = new ConcurrentDictionary<PropertyInfo, IPropertyAccessor>(); public static IPropertyAccessor GetAccessor(PropertyInfo propertyInfo) { IPropertyAccessor result = null; if (!_cache.TryGetValue(propertyInfo, out result)) { result = CreateAccessor(propertyInfo); _cache.TryAdd(propertyInfo, result); ; } return result; } public static IPropertyAccessor CreateAccessor(PropertyInfo PropertyInfo) { var GenType = typeof(PropertyWrapper<,>) .MakeGenericType(PropertyInfo.DeclaringType, PropertyInfo.PropertyType); return (IPropertyAccessor)Activator.CreateInstance(GenType, PropertyInfo); } } internal class PropertyWrapper<TObject, TValue> : IPropertyAccessor where TObject : class { private Func<TObject, TValue> Getter; private Action<TObject, TValue> Setter; public PropertyWrapper(PropertyInfo PropertyInfo) { this.PropertyInfo = PropertyInfo; MethodInfo GetterInfo = PropertyInfo.GetGetMethod(true); MethodInfo SetterInfo = PropertyInfo.GetSetMethod(true); Getter = (Func<TObject, TValue>)Delegate.CreateDelegate (typeof(Func<TObject, TValue>), GetterInfo); Setter = (Action<TObject, TValue>)Delegate.CreateDelegate (typeof(Action<TObject, TValue>), SetterInfo); } object IPropertyAccessor.GetValue(object source) { return Getter(source as TObject); } void IPropertyAccessor.SetValue(object source, object value) { Setter(source as TObject, (TValue)value); } public PropertyInfo PropertyInfo { get; private set; } } }
Use it like this:
public class MyClass { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } } MyClass e = new MyClass(); IPropertyAccessor[] Accessors = e.GetType().GetProperties() .Select(pi => PropertyInfoHelper.CreateAccessor(pi)).ToArray(); foreach (var Accessor in Accessors) { Type pt = Accessor.PropertyInfo.PropertyType; if (pt == typeof(string)) Accessor.SetValue(e, Guid.NewGuid().ToString("n").Substring(0, 9)); else if (pt == typeof(int)) Accessor.SetValue(e, new Random().Next(0, int.MaxValue)); Console.WriteLine(string.Format("{0}:{1}", Accessor.PropertyInfo.Name, Accessor.GetValue(e))); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With