Функции с неизвестным количеством параметров
рассмотрим следующий псевдо-код:
TResult Foo<TResult>(Func<T1, T2,...,Tn, TResult> f, params object[] args)
{
TResult result = f(args);
return result;
}
функция принимает Func<>
с неизвестным количеством общих параметров и списком соответствующих аргументов. Можно ли написать его на C#? Как определить и вызвать Foo
? Как пройти args
to f
?
4 ответов
Это невозможно. В лучшем случае у вас может быть делегат, который также принимает переменное количество аргументов, а затем делегат анализирует аргументы
TResult Foo<TResult>(Func<object[], TResult> f, params object[] args)
{
TResult result = f(args);
return result;
}
Foo<int>(args =>
{
var name = args[0] as string;
var age = (int) args[1];
//...
return age;
}, arg1, arg2, arg3);
можно использовать Delegate
С DynamicInvoke
.
С этим вам не нужно справляться с object[]
на f
.
TResult Foo<TResult>(Delegate f, params object[] args)
{
var result = f.DynamicInvoke(args);
return (TResult)Convert.ChangeType(result, typeof(TResult));
}
использование:
Func<string, int, bool, bool> f = (name, age, active) =>
{
if (name == "Jon" && age == 40 && active)
{
return true;
}
return false;
};
Foo<bool>(f,"Jon", 40, true);
Я создал скрипку, показывающую некоторые примеры:https://dotnetfiddle.net/LdmOqo
Примечание:
если вы хотите использовать method group
, вам нужно использовать explict casting для Func
:
public static bool Method(string name, int age)
{
...
}
var method = (Func<string, int, bool>)Method;
Foo<bool>(method, "Jon", 40);
Скрипка: https://dotnetfiddle.net/3ZPLsY
в некоторых случаях вам может сойти с рук такой трюк:
public static class MyClass
{
private static T CommonWorkMethod<T>(Func<T> wishMultipleArgsFunc)
{
// ... do common preparation
T returnValue = wishMultipleArgsFunc();
// ... do common cleanup
return returnValue;
}
public static int DoCommonWorkNoParams() => CommonWorkMethod<int>(ProduceIntWithNoParams);
public static long DoCommonWorkWithLong(long p1) => CommonWorkMethod<long>(() => ProcessOneLong(p1));
public static string DoCommonWorkWith2Params(int p1, long p2) => CommonWorkMethod<string>(() => ConvertToCollatedString(p1, p2));
private static int ProduceIntWithNoParams() { return 5; }
}
вы можете попробовать что-то похожее на то, что я разместил здесь:https://stackoverflow.com/a/47556051/4681344
Он допускает любое количество аргументов и применяет их типы.
public delegate T ParamsAction<T>(params object[] args);
TResult Foo<TResult>(ParamsAction<TResult> f)
{
TResult result = f();
return TResult;
}
назвать это просто...
Foo(args => MethodToCallback("Bar", 123));