Create a delegate from Methodinfo with generic parameter

Question

This Content is from Stack Overflow. Question asked by christoph

Based on this old but very usefull article by the legendary Jon Skeet, I wrote a few methods to genereate Action Delegates from MethodInfos for faster invokations. But I ran into an issue, where I am unable to make any progress. See the example below:

public class DataContainer
{
    public List<int> myList;

    public DataContainer()
    {
        myList = new List<int>() { 1, 2, 3, 4 };
    }
}

public static class ExtensionMethods
{
    public static void DoStuff<T>(this IList<T> items)
    {
    }
}

public class Example
{
    private Action<object> doStuffQuickly;

    public void Test()
    {
        var fieldInfo = typeof(DataContainer).GetField("myList");

        var doStuffMethod = typeof(ExtensionMethods).GetMethod("DoStuff", BindingFlags.Public | BindingFlags.Static);
        var listType = typeof(IList<>).MakeGenericType(fieldInfo.FieldType.GenericTypeArguments);
        doStuffQuickly = QuickAccess.CreateWeakActionWithOneParam(doStuffMethod, listType);

        var data = new DataContainer();
        var list = fieldInfo.GetValue(data);

        doStuffQuickly(list);
    }
}

public static class QuickAccess
{
    private static MethodInfo _weak1ParamActionCreator;
    private static MethodInfo Weak1ParamActionCreator => _weak1ParamActionCreator
        ??= typeof(QuickAccess).GetMethod(nameof(CreateWeakExplicit1ParamAction), BindingFlags.Static | BindingFlags.NonPublic);

    public static Action<object> CreateWeakActionWithOneParam(MethodInfo methodInfo, Type paramType0 = null)
    {
        var parameters = methodInfo.GetParameters();
        paramType0 ??= parameters[0].ParameterType;
        var creationMethod = Weak1ParamActionCreator.MakeGenericMethod(paramType0);
        return (Action<object>)creationMethod.Invoke(null, new object[] { methodInfo });
    }

    private static Action<object> CreateWeakExplicit1ParamAction<TValue>(MethodInfo methodInfo)
    {
        var action = CreateStrongExplicit1ParamAction<TValue>(methodInfo);
        return (object value) => action((TValue)value);
    }

    private static Action<TValue> CreateStrongExplicit1ParamAction<TValue>(MethodInfo methodInfo)
    {
        //Debug.Log(methodInfo.GetParameters()[0].ParameterType.Name + " <-> " + typeof(TValue).Name);
        //Debug.Log(PrintTypes(methodInfo.GetParameters()[0].ParameterType.GenericTypeArguments) + " <-> "
        //    + PrintTypes(typeof(TValue).GenericTypeArguments));
        return (Action<TValue>)Delegate.CreateDelegate(typeof(Action<TValue>), methodInfo);
    }

    private static string PrintTypes(Type[] types)
    {
        return string.Join(", ", types.Select(t => t.Name));
    }
}

This fails with ArgumentException: method arguments are incompatible when trying to create the delegate.
The commented logs print IList`1 <-> IList`1 and T <-> Int32, which made me think that maybe

var listType = typeof(IList<>).MakeGenericType(fieldInfo.FieldType.GenericTypeArguments);

should instead simply be

var listType = typeof(IList<>);

but that is causing an InvalidOperationException: Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.

I don’t know how to proceed from here. Any help will be appreciated.



Solution

Check the Answers


For more tutorials visit Jtuto.com


This Question and Answer are collected from stackoverflow and tested by JTuto community, is licensed under the terms of CC BY-SA 4.0.

people found this article helpful. What about you?