how do I dynamically create Func<t1, t2>?

N

not_a_commie

I'm struggling here. Please help me complete this method:

Type ToFuncType(Type owningType, Type result)
{
return typeof(Func<typeof(owningType), typeof(result)>);
}

Or more generally, given a MethodInfo from GetGetMethod, what is the
fastest way to get a delegate to the method? I can hard-code the Func
type with Delegate.CreateDelegate and it does exactly what I want. I
just don't know how to dynamically get that from the MethodInfo.
 
N

not_a_commie

I figured it out. Alas, my plan failed miserably. I was trying to find
the fastest way to invoke 'get' methods. Anybody have a faster method
of getting data than those below? Here is my test code:

using System;
using System.Diagnostics;
using System.Reflection;
using NUnit.Framework;

namespace Asi.Tests.Xml
{
[TestFixture]
public class DynamicInvoker
{
public class Inker
{
public int Count;
public int ReadAndInc1 { get { return Count++; } }
public int ReadAndInc2 { get { return Count++; } }
public int ReadAndInc3 { get { return Count++; } }
public int ReadAndInc4 { get { return Count++; } }
public int ReadAndInc5 { get { return Count++; } }
}

static public TR RunFunc<T, TR>(MethodInfo meth, T target)
{
var func = (Func<T, TR>) Delegate.CreateDelegate(typeof (Func<T,
TR>), meth);
return func.Invoke(target);
}

public object InvokeFunc(MethodInfo meth, object obj)
{
if(!meth.ReflectedType.Equals(obj.GetType()))
throw new InvalidOperationException();
_makerSW.Start();
var genmeth = _maker.MakeGenericMethod(meth.ReflectedType,
meth.ReturnType);
_makerSW.Stop();
object ret = genmeth.Invoke(this, new[] { meth, obj });
return ret;
}

private MethodInfo _maker;
private readonly Stopwatch _makerSW = new Stopwatch();

[Test][Explicit("Too slow normally")]
public void DynamicInvokeSpeed()
{
var rand = new Random();
var sw1 = new Stopwatch();
var i1 = new Inker();
sw1.Reset(); sw1.Start();
object cnt = -1;
for (int i = 0; i < 100000; i++)
{
var prop = i1.GetType().GetProperty("ReadAndInc" + rand.Next(1,
5));
var meth = prop.GetGetMethod();
var del = (Func<Inker,
int>)Delegate.CreateDelegate(typeof(Func<Inker, int>), meth);
cnt = del.Invoke(i1);
}
Console.Out.WriteLine("hard-coded took " +
sw1.Elapsed.TotalSeconds);

var parms = new object[] { };
_maker = GetType().GetMethod("RunFunc", BindingFlags.Static |
BindingFlags.Public);
_makerSW.Reset();
sw1.Reset(); sw1.Start();
for (int i = 0; i < 100000; i++)
{
var prop = i1.GetType().GetProperty("ReadAndInc" + rand.Next(1,
5));
var meth = prop.GetGetMethod();
cnt = InvokeFunc(meth, i1);
}
Console.Out.WriteLine("Dynamic took " + sw1.Elapsed.TotalSeconds);
Console.Out.WriteLine("GenericMaker took " +
_makerSW.Elapsed.TotalSeconds);

sw1.Reset(); sw1.Start();
for (int i = 0; i < 100000; i++)
{
var prop = i1.GetType().GetProperty("ReadAndInc" + rand.Next(1,
5));
var meth = prop.GetGetMethod();
cnt = meth.Invoke(i1, parms);
}
Console.Out.WriteLine("Invoke took " + sw1.Elapsed.TotalSeconds);

sw1.Reset(); sw1.Start();
for (int i = 0; i < 100000; i++)
{
var prop = i1.GetType().GetProperty("ReadAndInc" + rand.Next(1,
5));
cnt = prop.GetValue(i1, null);
}
Console.Out.WriteLine("Reflect took " + sw1.Elapsed.TotalSeconds);
Console.Out.WriteLine("Cnt = " + cnt);
}
}
}
 
N

not_a_commie

Thanks for the reply. Jon Skeet's article was the inspiration that
made me look into this approach. From my test of his method, there
would be no benefit unless you were repeatedly calling the same method
over and over. Typical (de)serialization doesn't do that. It only hits
each method once. There is probably some fancy DynamicMethod + IL
approach, but I don't know what it is. I did come up with another
approach (that is still not the fastest):

var prop = i1.GetType().GetProperty("ReadAndInc" + rand.Next(1, 5));
var meth = prop.GetGetMethod();
var dyn = DynamicMethod.GetMethodFromHandle(meth.MethodHandle);
cnt = dyn.Invoke(i1, parms);
 
J

Jon Skeet [C# MVP]

not_a_commie said:
Thanks for the reply. Jon Skeet's article was the inspiration that
made me look into this approach. From my test of his method, there
would be no benefit unless you were repeatedly calling the same method
over and over. Typical (de)serialization doesn't do that.

Ironically serialization is *exactly* the scenario that I was working
on. Yes, you only need to call the method once for a single object
being serialized, but IME you typically need to serialize/deserialize
many objects of the same type in the course of a program.

If you're only calling the method once, why do you want to create a
delegate from it in the first place?
 
N

not_a_commie

Thank you for the suggestions. I have some small geometry objects that
are serialized many times. I will modify my serialization attributes
on those to cache the appropriate delegates.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top