What you’re doing here does not work at all. Your RegisterCommand seems to expect a parameterless action. Therefore you can not pass any arguments to the methods you register here. You create a wrapper lambda expression like this:
() => AddHealth()
That means you create a new anonymous method that doesn’t have any arguments at all. inside the body of that method youc all your AddHealth method. Since you don’t pass any arguments to your AddHealth method, your default argument of “0” applies here. So your lambda expression is equivalent to this:
void AnonymousMethod()
{
AddHealth(0);
}
So you register a delegate to this “AnonymousMethod”. You can’t pass arguments to a delegate that does not have any arguments. To me it’s still not really clear what you want to do. DynamicInvoke doesn’t allow you do change or omit arguments. All it does is late bind the method and arguments. However you still have to provide the exact same number of arguments with the exact types.
If this is about some kind of console commands, you probably want to change the delegate type to something that takes a params string array. That way each method could interpret / convert the arguments as they need. You can not store different delegate types into a single delegate type. C# is a strongly typed language. The most flexible approach is to use an object array which allows all sorts of arguments, however the method has to check, interpret, convert the arguments itself.
Of course you could build some kind of mediating layer that helps to manually convert the arguments as you create the lambda expression.
So I would suggest to first change the delegate type of your command system to something like
public delegate void UserCommand(params string[] aArgs);
That way the calling system is free to pass any number of string arguments to the registered methods. All those methods would receive a string array with the potential variable arguments.
As a second step you may want to write a few extension methods that would help you to manually convert, parse and handle the arguments when you create your lambda expression. Here are a few examples:
public static class ArgumentArrayExtensions
{
public static float ArgFloat(this string[] aArgs, int aIndex)
{
if (aArgs == null || aIndex < 0 || aIndex >= aArgs.Length)
throw new System.Exception("Wrong argument count");
if (float.TryParse(aArgs[aIndex], out float value))
return value;
throw new System.Exception("Passed argument can't be parsed as float");
}
public static int ArgInt(this string[] aArgs, int aIndex)
{
if (aArgs == null || aIndex < 0 || aIndex >= aArgs.Length)
throw new System.Exception("Wrong argument count");
if (int.TryParse(aArgs[aIndex], out int value))
return value;
throw new System.Exception("Passed argument can't be parsed as float");
}
public static float ArgFloatDefault(this string[] aArgs, int aIndex, float aDefault = 0f)
{
if (aArgs == null || aIndex < 0 || aIndex >= aArgs.Length)
return aDefault;
if (float.TryParse(aArgs[aIndex], out float value))
return value;
return aDefault;
}
public static int ArgIntDefault(this string[] aArgs, int aIndex, int aDefault = 0)
{
if (aArgs == null || aIndex < 0 || aIndex >= aArgs.Length)
return aDefault;
if (int.TryParse(aArgs[aIndex], out int value))
return value;
return aDefault;
}
}
Those extension methods for a string array would allow you to grab and convert a certain argument to the desired type. The first two variants would throw an error when something’s not right, the last two examples allows you to specify a default value that is used in case the argument is not provided or the argument could not be converted into the desired type.
When you register your “AddHealth” method you could do this:
RegisterCommands(
"SetHealth",
"Adds a specified amount of health to the player",
args => Arcane_GameManager.manager.AddHealth(args.ArgIntDefault(0, 5)),
false, false
);
In this case “RegisterCommands” (which should be called RegisterCommand) would take a UserCommand delegate. The “args” is our string array. So every command would get this string array. We use the ArgIntDefault extension method to get the value at index 0 and convert it into an integer and pass it to the actual method we want to call. If something is wrong (no argument or the first argument can not be converted into an integer) the ArgIntDefault method would return a value of 5, so we can savely call the AddHealth method because we have to pass an int argument.
Of course you could add more such utility methods to get other arguments like Vector3 or whatever you may also need for your commands.