Consider the following pseudo code:
TResult Foo<TResult>(Func<T1, T2,...,Tn, TResult> f, params object[] args)
{
TResult result = f(args);
return result;
}
The function accepts Func<> with unknown number of generic parameters and a list of the corresponding arguments. Is it possible to write it in C#? How to define and call Foo? How do I pass args to f?
That's not possible. At best, you could have a delegate that also takes a variable number of arguments, and then have the delegate parse the arguments
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);
You can use Delegate with DynamicInvoke.
With that, you don't need to handle with object[] in f.
TResult Foo<TResult>(Delegate f, params object[] args)
{
var result = f.DynamicInvoke(args);
return (TResult)Convert.ChangeType(result, typeof(TResult));
}
Usage:
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);
I created a fiddle showing some examples: https://dotnetfiddle.net/LdmOqo
Note:
If you want to use a method group, you need to use an explict casting to Func:
public static bool Method(string name, int age)
{
...
}
var method = (Func<string, int, bool>)Method;
Foo<bool>(method, "Jon", 40);
Fiddle: https://dotnetfiddle.net/3ZPLsY
This could become easy with lambda expressions:
TResult Foo<Tresult>(Func<TResult> f)
{
TResult result = f();
return result;
}
Then usage coul be like:
var result = Foo<int>(() => method(arg1, arg2, arg3));
Where method can be arbitrary method returning int.
This way you can pass any number of any erguments directly through lambda.
You could try something similar to what I posted here: https://stackoverflow.com/a/47556051/4681344
It will allow for any number of arguments, and enforces their types.
public delegate T ParamsAction<T>(params object[] args);
TResult Foo<TResult>(ParamsAction<TResult> f)
{
TResult result = f();
return result;
}
to call it, simply......
Foo(args => MethodToCallback("Bar", 123));
In some cases you may be able to get away with a trick like this:
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/questions/22834120/func-with-unknown-number-of-parameters