Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Parameters do not match signature with DynamicInvoke

Discussion in 'Scripting' started by ATLAS-INTERACTIVE, Jul 3, 2022.

  1. ATLAS-INTERACTIVE

    ATLAS-INTERACTIVE

    Joined:
    Mar 3, 2014
    Posts:
    1,385
    Hi everyone, I'm trying to build an internal command console and I've run into a weird error I've never seen before, I'm getting the following when trying to pass parameters via DynamicInvoke:
    Code (CSharp):
    1. TargetParameterCountException: parameters do not match signature
    The code benig used to call it looks something like this:
    Code (CSharp):
    1. string args = input.Remove(0, input.IndexOf(' ') + 1);
    2. libLv3.Key.DynamicInvoke(args);
    Essentially, I'm stripping out anything before the first space (the command) and applying the remainder as an argument to the method, which is stored as an Action.
    To allow the Action to reference a method with arguments, I'm using a parameterless lambda to prevent the "cannot convert from method group to action", which I think may be the issue.
    Code (CSharp):
    1. console.RegisterCommands("GiveHealth", "Gives player a set amount of health", () => GiveHealth(), true, false);
    2.  
    3. void GiveHealth(int amount = 0)
    4.     {
    5.         Arcane_GameManager.manager.AddHealth(amount);
    6.     }
    I can't seem to work out how to produce a generic solution to allow me to register commands, some of which can take arguments without the arguments simply not working. What exactly am I doing wrong here? Is it the lambda conversion preventing arguments being passed?
     
  2. Hikiko66

    Hikiko66

    Joined:
    May 5, 2013
    Posts:
    1,237
    Looks like the args are supposed to be an array of objects, not a string
    https://www.thecodeteacher.com/question/29212/c

    That doesn't work. You'd need to include the arguments in that lambda call for it to work, but then that action will only ever be able to invoke with those arguments.
     
    Last edited: Jul 3, 2022
  3. ATLAS-INTERACTIVE

    ATLAS-INTERACTIVE

    Joined:
    Mar 3, 2014
    Posts:
    1,385
    I've reworked things to place the args in an array, but I'm still getting the same error:
    Code (CSharp):
    1. string args = input.Remove(0, input.IndexOf(' ') + 1);
    2.                                     string[] argArray = args.Split(' ');
    3.                                     libLv3.Key.DynamicInvoke(argArray);
     
  4. Hikiko66

    Hikiko66

    Joined:
    May 5, 2013
    Posts:
    1,237
    Maybe this will shed some light

    Using reflection we get the type of the class we are in
    We fetch the function we are interested in
    We fetch the parameters of the function we are interested in
    We convert our string parameters to the appropriate parameter types
    We then add those converted parameters to an object list
    We invoke the method with the parameter object list as an array

    That works. If we don't convert those parameters to their proper types, it fails for both invoke and dynamic invoke.
    DynamicInvoke seemingly requires us to declare an action/func with those parameters?
    Invoke doesn't

    LocalMethodCall "CalculateAgeThisYear 2000"


    Code (CSharp):
    1.  
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.Reflection;
    6. using UnityEngine;
    7.  
    8. public class ReflectionMethod : MonoBehaviour
    9. {
    10.     public string LocalMethodCall;
    11.     private string functionname;
    12.     private List<object> parameters = new();
    13.     // Start is called before the first frame update
    14.     void Start()
    15.     {
    16.         Type thisType = this.GetType();
    17.  
    18.         var methodCallsplit = LocalMethodCall.Split(' ');
    19.         functionname = methodCallsplit[0];
    20.  
    21.         MethodInfo theMethod = thisType.GetMethod(functionname);
    22.  
    23.         ParameterInfo[] paraminfo = theMethod.GetParameters();
    24.  
    25.         for (int i = 1; i < methodCallsplit.Length; i++)
    26.         {
    27.             var param = Convert.ChangeType(methodCallsplit[i], paraminfo[i-1].ParameterType);
    28.             parameters.Add(param);
    29.  
    30.         }
    31.  
    32.         //invoke
    33.         theMethod.Invoke(this, parameters.ToArray());
    34.  
    35.         //dynamicinvoke
    36.         Action<int> act = CalculateAgeThisYear;
    37.         act.DynamicInvoke(parameters.ToArray());
    38.     }
    39.  
    40.     public void CalculateAgeThisYear(int yearOfBirth )
    41.     {
    42.         Debug.Log($"Age: {DateTime.Now.Year - yearOfBirth}");
    43.     }
    44. }
     
  5. Hikiko66

    Hikiko66

    Joined:
    May 5, 2013
    Posts:
    1,237
    I did find out how to create a delegate at runtime with variable parameters for the dynamicinvoke.
    Haven't looked into funcs and returns or anything

    Code (CSharp):
    1.  
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.Reflection;
    6. using UnityEngine;
    7.  
    8. public class ReflectionMethod : MonoBehaviour
    9. {
    10.     private string LocalMethodCall1 = "CalculateAgeThisYear 2000";
    11.     private string LocalMethodCall2 = "Test";
    12.  
    13.     private delegate void Del();
    14.  
    15.     // Start is called before the first frame update
    16.     void Start()
    17.     {
    18.         ReflectionInvoke(LocalMethodCall1);
    19.         ReflectionInvoke(LocalMethodCall2);
    20.  
    21.         //dynamicinvoke
    22.         //Action<int> act = CalculateAgeThisYear;
    23.         //act.DynamicInvoke(parameters.ToArray());
    24.     }
    25.  
    26.     public void ReflectionInvoke(string methodCall)
    27.     {
    28.         string functionname;
    29.         List<object> parameters = new();
    30.  
    31.         Type thisType = this.GetType();
    32.  
    33.         var methodCallsplit = methodCall.Split(' ');
    34.         functionname = methodCallsplit[0];
    35.  
    36.         MethodInfo theMethod = thisType.GetMethod(functionname);
    37.  
    38.         ParameterInfo[] paraminfo = theMethod.GetParameters();
    39.         List<System.Type> paramTypes = new();
    40.  
    41.         for (int i = 1; i < methodCallsplit.Length; i++)
    42.         {
    43.             paramTypes.Add(paraminfo[i - 1].ParameterType);
    44.             var param = Convert.ChangeType(methodCallsplit[i], paraminfo[i - 1].ParameterType);
    45.             parameters.Add(param);
    46.  
    47.         }
    48.  
    49.         //Invoke
    50.         theMethod.Invoke(this, parameters.ToArray());
    51.  
    52.         //Dynamic Invoke
    53.         var actionType = System.Linq.Expressions.Expression.GetActionType(paramTypes.ToArray());
    54.         Delegate act = theMethod.CreateDelegate(actionType, this);
    55.         act.DynamicInvoke(parameters.ToArray());
    56.     }
    57.  
    58.     public void CalculateAgeThisYear(int yearOfBirth )
    59.     {
    60.         Debug.Log($"Age: {DateTime.Now.Year - yearOfBirth}");
    61.     }
    62.  
    63.     public void Test()
    64.     {
    65.         Debug.Log("Ran Parameterless Test");
    66.     }
    67.  
    68. }
     
  6. ATLAS-INTERACTIVE

    ATLAS-INTERACTIVE

    Joined:
    Mar 3, 2014
    Posts:
    1,385
    This seems like more what I'm after, but you seem to be using MethodInfo to create a delegate, how do you do that? Your code just gives me a "MethodInfo does not contain a definition for CreateDelegate" error.
     
unityunity