1

I'm trying to call a method in an aspx.cs but getting an InvalidOperationException with message

Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.

My code is:

protected void BuildSurface(int newValue)
{
    IEnumerable<dynamic> models = InitializeConfigurationForWorkflow(newValue);
    List<Panel> panelList = new List<Panel>();

    foreach (dynamic workflowConfiguration in models)
    {
        Type dynamicType = workflowConfiguration.GetType();

        if (dynamicType.IsGenericType)
        {
            Type genericDynamicType = dynamicType.GetGenericTypeDefinition();

            string methodName = null;
            if (genericDynamicType.In(typeof(List<>), typeof(IEnumerable<>), typeof(IList<>)))
                methodName = "GenerateListPanel";
            else if (genericDynamicType == typeof(Dictionary<,>))
                methodName = "GenerateDictionaryPanel";

            if (methodName.IsNullOrEmpty()) continue;

            Type[] listType = genericDynamicType.GetGenericArguments();
            MethodInfo method = typeof(_admin_WorkflowConfiguration)
                .GetMethods()
                .Where(w => w.Name.Equals(methodName))
                .First();

            MethodInfo generic = method.MakeGenericMethod(listType);
            panelList.Add(generic.Invoke(this, workflowConfiguration})); // here the error appears
        }
    }
}

my methods that will be called look like this one:

public Panel GenerateListPanel<T>(IEnumerable<T> workflowConfiguration)
{
    Panel panel = new Panel();
    return panel;
}

The dynamic-value is a json that gets deserialized to either Dictionary or List.

Any idea what I'm doing wrong?

Matthias Burger
  • 5,549
  • 7
  • 49
  • 94

2 Answers2

1

Since you are passing an instance workflowConfiguration of a concrete generic type dynamicType, you need to use its concrete generic arguments in invoking a generic method that uses it as an argument.

Thus if your methods GenerateListPanel and GenerateDictionaryPanel have signatures like:

public Panel GenerateListPanel<T>(IEnumerable<T> workflowConfiguration)

public Panel GenerateDictionaryPanel<TKey, TValue>(IDictionary<TKey, TValue> workflowConfiguration)

You should do:

Type[] listType = dynamicType.GetGenericArguments();

I think you also need to cast the return of generic.Invoke() to a Panel.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • you are a genius! :) Thanks man! I also needed to change `workflowConfiguration` to `new object[] { workflowConfiguration }` when calling `Invoke`. – Matthias Burger Jun 10 '16 at 11:48
1

There's another solution not involving calling method with reflection. Have a look at this:

if (dynamicType.IsGenericType)
            {
                var genericDynamicType = dynamicType.GetGenericTypeDefinition();

                Func<Panel> generatePanelMethod = null;
                if (genericDynamicType.In(typeof (List<>), typeof (IEnumerable<>), typeof (IList<>)))
                    generatePanelMethod = () => this.GenerateListPanel(workflowConfiguration);
                else if (genericDynamicType == typeof(Dictionary<,>))
                    generatePanelMethod = () => this.GenerateDictionaryPanel(workflowConfiguration);

                if (generatePanelMethod == null) continue;

                panelList.Add(generatePanelMethod());
            }
Aleksey L.
  • 35,047
  • 10
  • 74
  • 84