MakeGenericMethod/MakeGenericType on Xamarin.iOS

2019-03-21 03:11发布

问题:

I'm trying to figure out what the limitations really means when deploying for iOS from Xamarin.

http://developer.xamarin.com/guides/ios/advanced_topics/limitations/

I was under the impression that you have no JIT and thus any MakeGenericMethod or MakeGenericType would NOT work as that would require JIT compilation.

Also I understood that when running on the simulator, these restrictions does not apply since the simulator is not running in the full AOT (Ahead of Time) mode.

After setting up my Mac so that I could deploy to my phone, I would except the following test to fail when running on the actual device (iPhone).

    [Test]
    public void InvokeGenericMethod()
    {
        var method = typeof(SampleTests).GetMethod ("SomeGenericMethod");

        var closedMethod = method.MakeGenericMethod (GetTypeArgument());

        closedMethod.Invoke (null, new object[]{42});

    }

    public static void SomeGenericMethod<T>(T value)
    {
    }


    private Type GetTypeArgument()
    {
        return typeof(int);
    }

The thing is that completes successfully and I can't really understand why. Does not this code require JIT compilation?

In an effort to "make it break" , I also did a test with MakeGenericType.

    [Test]
    public void InvokeGenericType()
    {
        var type = typeof(SomeGenericClass<>).MakeGenericType (typeof(string));

        var instance = Activator.CreateInstance (type);

        var method = type.GetMethod ("Execute");

        method.Invoke (instance, new object[]{"Test"});

    }


public class SomeGenericClass<T>
{
    public void Execute(T value)
    {

    }
}

How can this work when there is no JIT?

Am I missing something ?

回答1:

In order to make the code fail go to iOS project options, tab "iOS Build" and change the "Linker Behavior:" to "Link all assemblies". Running the code will result in Exception and it will be of type default constructor for type XXX was not found.

Now, make a reference to the SomeGenericClass{string} in your code and the method will run just fine. The two added lines cause the compiler to include SomeGenericClass{string} in the binary. Note that the lines can be anywhere in the application that is compiled into the binary, they don't have to be in the same function.

    public void InvokeGenericType()
    {
        // comment out the two lines below to make the code fail
        var strClass = new SomeGenericClass<string>();
        strClass.Execute("Test");

        var type = typeof(SomeGenericClass<>).MakeGenericType (typeof(string));

        var instance = Activator.CreateInstance (type);

        var method = type.GetMethod ("Execute");

        method.Invoke (instance, new object[]{"Test"});
    }