Edit:
Also important: note that I am using typeof(object).GetMethod(...)
, not typeof(T).GetMethod(...)
- your line argument_type.GetType().GetMethod( "ToString" );
looks very suspect IMO.
I suspect the issue is that you are loading a local/argument, rather than the address of a local/argument - in the line immediately before what is shown. Constrained
needs this so that it can correctly perform the static-call implementation; for the virtual-call implementation, it can simply dereference this to get the actual reference.
Other than that: Constrained
should work fine - see below (in particular, note the Ldarga_S
). Of course, another option is to use Box
, but this will have more overhead. Constrained
is the ideal way of calling ToString
on an arbitrary type.
using System;
using System.Reflection.Emit;
public class RefTypeNoImpl { }
public class RefTypeImpl { public override string ToString() { return "foo"; } }
public struct ValTypeNoImpl { }
public struct ValTypeImpl { public override string ToString() { return "bar"; } }
static class Program
{
static void Main()
{
Test<RefTypeNoImpl>();
Test<RefTypeImpl>();
Test<ValTypeNoImpl>();
Test<ValTypeImpl>();
}
static void Test<T>() where T : new()
{
var dm = new DynamicMethod("foo", typeof(string), new[] { typeof(T) });
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarga_S, 0);
il.Emit(OpCodes.Constrained, typeof(T));
il.Emit(OpCodes.Callvirt, typeof(object).GetMethod("ToString"));
il.Emit(OpCodes.Ret);
var method = (Func<T, string>)dm.CreateDelegate(typeof(Func<T, string>));
Console.WriteLine(method(new T()));
}
}