コードを追加するだけです...なぜなら。コードは満足のいくものではありません、私は同意しますが、それはかなり簡単です。うまくいけば、これはこれに遭遇する誰かを助けるでしょう。テストされていますが、実稼働環境で必要なほどではない可能性があります。
引数argsを使用してオブジェクトobjでメソッドmethodNameを呼び出す:
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);
}
そして、関数ArgumentListMatchesは以下のとおりです。これは、基本的に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);
}
たくさんのLINQがあり、これはパフォーマンステストされていません!
また、これはジェネリック関数またはメソッド呼び出しを処理しません。これにより、これは非常に醜くなります(GetMethod呼び出しを繰り返す場合のように)。