I have been testing out using delegates instead of reflection for some object sorting and it was working good for string properties, but if I try an Int (or DateTime) it fails and throws
Error binding to target method.
class Program
{
static void Main(string[] args)
{
var sample = new SampleClass() { Num = 13, Text = "Sample" };
Console.WriteLine(ReadProp(sample,"Text")); //Works
Console.WriteLine(ReadProp(sample, "classProp")); //Works
Console.WriteLine(ReadProp(sample, "Num")); //Throws 'Error binding to target method.'
}
//Use a Delegate to improve speed of accessing property instead of reflection
static object ReadProp(SampleClass obj, string propName)
{
var method = obj.GetType().GetProperty(propName).GetGetMethod();
var getForProp = (Func<SampleClass, object>)Delegate.CreateDelegate(typeof(Func<SampleClass, object>), null, method);
return getForProp(obj);
}
}
//A sample class for illustration purposes
class SampleClass
{
public string Text { get; set; }
public int Num { get; set; }
public SampleClass classProp { get; set; }
}
My question is: Why does it work for strings or other classes but not for Int or DateTime?
I can see that if I change my Func<SampleClass, object> to Func<SampleClass, int> it will then work for my Int but I expected object would work for both.
Because a method which returns an
intisn’t a method which returns anobjectreference. There has to be a boxing conversion – so something’s got to do that, andDelegate.CreateDelegateis trying to provide a delegate which just invokes the delegate and returns the result, with no value conversion involved.It’s slightly painful to do, but basically I suspect you should either be building a
Funcwith an appropriate return value and using that directly or you should go via a wrapper delegate which calls the “real” delegate and boxes the result.(Note that in your sample code, you’re creating the delegate each time, which is going to be no faster than reflection. Hopefully your real code is more sensible 🙂
If you look at this code from
protobuf-csharp-portyou’ll see I’ve got a method to do exactly this – a lambda expression calls the strongly-typed delegate, and then uses the implicit conversion toobject(boxing where necessary) to provide the value. You should be able to use something very similar. However, if you’re sorting do you really want aFunc<T, object>? If you use a strongly-typed delegate instead, you may be able to avoid all this boxing.