RuntimeHelpers.PrepareMethod not working when called with Func<string> created in Generic class

时间:2015-07-31 20:10:14

标签: c# .net reflection il runtime-compilation

I'm currently working on an extension on the Moq framework to be also to mock the implementation of non virtual methods. I currently already have this working by obtaining the Method Handle of the original Method and swapping this with the pointer of a user defined Func.

One issue I'm still running into is that when I create the Func in the Moq internal code (inside a class that uses Generics) I run into an issue with RuntimeHelpers.PrepareMethod. (The Func needs to be prepared before we can execute the pointer swap).

When I create exactly the same Func in a normal class (e.g. Program) everything works fine.

Further investigating the issue traced this back to wether the call class had generic arguments or not.

Exception being thrown:

An unhandled exception of type 'System.ArgumentException' occurred in mscorlib.dll

Additional information: The given generic instantiation was invalid.

I have isolated the problem in the following codeblock:

class Program
{
    static void Main(string[] args)
    {
        new WithoutGeneric().GoExecute();
        new WithGeneric<string>().GoExecute();
    }
}

public class WithoutGeneric
{
    public void GoExecute()
    {
        //Works fine
        StaticMethods.PrepareThisFunc(() => "Test");
    }
}

public class WithGeneric<T>
{
    public void GoExecute()
    {
        //Breaks
        StaticMethods.PrepareThisFunc(() => "Test");
    }
}

public static class StaticMethods
{
    public static void PrepareThisFunc(Func<string> theFunc)
    {
        RuntimeHelpers.PrepareMethod(theFunc.Method.MethodHandle);
    }
}

I have also looked at the current open source CoreCLR code but have not been able to find out what the issue might be.

CoreCLR: https://github.com/dotnet/coreclr/blob/master/src/vm/reflectioninvocation.cpp

The exception is thrown on the lines: 2435, 2444, 2447

Does anyone have an idea on how to resolve this exception?

1 个答案:

答案 0 :(得分:1)

The CLR is unknown to the type parameter in WithGeneric class, which it needs to know to create the call graph.

Doing this will solve the issue:

class Program
{
    static void Main(string[] args)
    {
        new WithoutGeneric().GoExecute();
        new WithGeneric<string>().GoExecute();
    }
}

public class WithoutGeneric
{
    public void GoExecute()
    {
        //Works fine
        StaticMethods.PrepareThisFunc1(() => "Test");
    }
}

public class WithGeneric<T>
{
    public void GoExecute()
    {
        //Works fine
        StaticMethods.PrepareThisFunc2(() => "Test");
    }
}

public static class StaticMethods
{
    public static void PrepareThisFunc1(Func<string> theFunc)
    {
        RuntimeHelpers.PrepareMethod(theFunc.Method.MethodHandle);
    }

    public static void PrepareThisFunc2(Func<string> theFunc)
    {
        RuntimeHelpers.PrepareMethod(theFunc.Method.MethodHandle, new[] { typeof(string).TypeHandle });
    }
}