I'll just add some code... because. The code isn't pleasent, I agree, but it is fairly straight forward. Hopefully this will help someone who stumbles accross this. It is tested, though probably not as well as you would want in a production environment:
Calling method methodName on object obj with arguments args:
public Tuple<bool, object> Evaluate(IScopeContext c, object obj, string methodName, object[] args)
{
// Get the type of the object
var t = obj.GetType();
var argListTypes = args.Select(a => a.GetType()).ToArray();
var funcs = (from m in t.GetMethods()
where m.Name == methodName
where m.ArgumentListMatches(argListTypes)
select m).ToArray();
if (funcs.Length != 1)
return new Tuple<bool, object>(false, null);
// And invoke the method and see what we can get back.
// Optional arguments means we have to fill things in.
var method = funcs[0];
object[] allArgs = args;
if (method.GetParameters().Length != args.Length)
{
var defaultArgs = method.GetParameters().Skip(args.Length)
.Select(a => a.HasDefaultValue ? a.DefaultValue : null);
allArgs = args.Concat(defaultArgs).ToArray();
}
var r = funcs[0].Invoke(obj, allArgs);
return new Tuple<bool, object>(true, r);
}
And the function ArgumentListMatches is below, which basically takes the place of the logic probably found in GetMethod:
public static bool ArgumentListMatches(this MethodInfo m, Type[] args)
{
// If there are less arguments, then it just doesn't matter.
var pInfo = m.GetParameters();
if (pInfo.Length < args.Length)
return false;
// Now, check compatibility of the first set of arguments.
var commonArgs = args.Zip(pInfo, (margs, pinfo) => Tuple.Create(margs, pinfo.ParameterType));
if (commonArgs.Where(t => !t.Item1.IsAssignableFrom(t.Item2)).Any())
return false;
// And make sure the last set of arguments are actually default!
return pInfo.Skip(args.Length).All(p => p.IsOptional);
}
Lots of LINQ, and this has not been performance tested!
Also, this will not handle generic function or method calls. That makes this significantly more ugly (as in repeated GetMethod calls).
MethodInfo
orConstructorInfo
? – Leibniz