Func<> 具有未知数量的参数
本文关键字:参数 未知数 Func | 更新日期: 2023-09-27 17:56:27
考虑以下伪代码:
TResult Foo<TResult>(Func<T1, T2,...,Tn, TResult> f, params object[] args)
{
TResult result = f(args);
return result;
}
该函数接受具有未知数量的泛型参数和相应参数列表的Func<>
。是否可以用 C# 编写它?如何定义和调用Foo
?如何将args
传递给f
?
您可以将
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
,则需要使用显式强制转换来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
这是不可能的。充其量,你可以有一个也接受可变数量的参数的委托,然后让委托分析参数
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);
使用 lambda 表达式可以变得很容易:
TResult Foo<TResult>(Func<TResult> f)
{
return f();
}
然后用法可以是这样的:
var result = Foo<int>(() => method(arg1, arg2, arg3));
其中method
可以是任意方法返回int
。
通过这种方式,您可以直接通过 lambda 传递任意数量的任意 ergus。
为了支持异步代码,我们可以定义:
Task<TResult> Foo<TResult>(Func<Task<TResult>> f)
{
return f();
}
// or with cancellation token
Task<TResult> Foo<TResult>(Func<CancellationToken, Task<TResult>> f, CancellationToken cancellationToken)
{
return f(cancellationToken);
}
并像这样使用它:
var asyncResult = await Foo(async () => await asyncMethod(arg1, arg2, arg3));
// With cancellation token
var asyncResult = await Foo(
async (ct) => await asyncMethod(arg1, arg2, arg3, ct),
cancellationToken);
你可以尝试类似于我在这里发布的内容:https://stackoverflow.com/a/47556051/4681344
它将允许任意数量的参数,并强制执行它们的类型。
public delegate T ParamsAction<T>(params object[] args);
TResult Foo<TResult>(ParamsAction<TResult> f)
{
TResult result = f();
return result;
}
简单地说...
Foo(args => MethodToCallback("Bar", 123));
在某些情况下,
您可以使用这样的技巧:
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; }
}
虽然这不是真正要求的内容,但一个简单的解决方法是使用不同数量的类型参数定义几个 Foo 方法。具有超过 6 个参数的函数并不常见,因此可以定义以下方法并摆脱几乎所有用例,同时保持类型安全。然后,Renan的解决方案可以用于其余的情况。
public TResult Foo<TResult> (Func<TResult> f)
{
return f();
}
public TResult Foo<T1, TResult>(Func<T1, TResult> f, T1 t1)
{
return f(t1);
}
public TResult Foo<T1, T2, TResult>(Func<T1, T2, TResult> f, T1 t1, T2 t2)
{
return f(t1, t2);
}
...