如何在 C# 中用未知数量和类型的参数包装 Func<T1...Tn>?
How to wrap a Func<T1...Tn> with unknown number and type of parameters in C#?
假设我有这个 class:
public class Function {
public int argc; //number of arguments of the function
public float[] argv;
public Func<float> f; //attribute to store a function (e.g. Sin(x) or Pow(a, b))
}
我想创建包含不同函数的 Function
实例,例如 Sin(x)
或 Pow(a, b)
,但我不知道如何绑定现有函数(使用任何数字参数)到 Func
。显然,它的声明并不总是 Func<float>
,而是 Func<float, float>
、Func<float, float, float>
等
我找过 Func
、delegate
、Action
,但仍然没有弄清楚如何让这个 "function capsule" 可以保存和执行函数不同数量的参数。为简单起见,我认为唯一的输入和输出类型是 float
.
我正在考虑使用类似 Func<List<float>>
的东西,但我想知道是否有更好的选择。
我想提出一个更准确地符合 OP 描述的场景的答案。关键在于 Delegate.DynamicInvoke
的用法,它允许您将无限数量的参数传递给委托。
public class Function<TReturn> {
private readonly object[] _argv;
private readonly Delegate _func;
public Function(Delegate func, params object[] args) {
_func = func;
_argv = args;
}
public TReturn Run() {
object v = _func.DynamicInvoke(_argv);
return (TReturn)v;
}
}
它的用法让您可以动态决定要传递的参数数量:
var s = new Function<double>((Func<double, double>)(x => Math.Sin(x)), 1 );
Console.WriteLine(s.Run()); // prints 0.8414709848078965
var p = new Function<double>((Func<double, double, double>)((a, b) => Math.Pow(a, b)), 2, 3);
Console.WriteLine(p.Run()); // prints 8
var d = new Function<string>((Func<string, double, string>)((a, b) => a + b.ToString()), "hello, ", 42);
Console.WriteLine(p.Run()); // prints "hello, 42"
请注意,类型检查仅在调用 Function.Run()
时在 运行 时执行,而不是在构造 Function
对象时执行,因为它具有动态特性。如果您确定所有传递的参数始终属于同一类型,则可以通过添加 TArg
泛型类型来静态强制执行。
假设我有这个 class:
public class Function {
public int argc; //number of arguments of the function
public float[] argv;
public Func<float> f; //attribute to store a function (e.g. Sin(x) or Pow(a, b))
}
我想创建包含不同函数的 Function
实例,例如 Sin(x)
或 Pow(a, b)
,但我不知道如何绑定现有函数(使用任何数字参数)到 Func
。显然,它的声明并不总是 Func<float>
,而是 Func<float, float>
、Func<float, float, float>
等
我找过 Func
、delegate
、Action
,但仍然没有弄清楚如何让这个 "function capsule" 可以保存和执行函数不同数量的参数。为简单起见,我认为唯一的输入和输出类型是 float
.
我正在考虑使用类似 Func<List<float>>
的东西,但我想知道是否有更好的选择。
我想提出一个更准确地符合 OP 描述的场景的答案。关键在于 Delegate.DynamicInvoke
的用法,它允许您将无限数量的参数传递给委托。
public class Function<TReturn> {
private readonly object[] _argv;
private readonly Delegate _func;
public Function(Delegate func, params object[] args) {
_func = func;
_argv = args;
}
public TReturn Run() {
object v = _func.DynamicInvoke(_argv);
return (TReturn)v;
}
}
它的用法让您可以动态决定要传递的参数数量:
var s = new Function<double>((Func<double, double>)(x => Math.Sin(x)), 1 );
Console.WriteLine(s.Run()); // prints 0.8414709848078965
var p = new Function<double>((Func<double, double, double>)((a, b) => Math.Pow(a, b)), 2, 3);
Console.WriteLine(p.Run()); // prints 8
var d = new Function<string>((Func<string, double, string>)((a, b) => a + b.ToString()), "hello, ", 42);
Console.WriteLine(p.Run()); // prints "hello, 42"
请注意,类型检查仅在调用 Function.Run()
时在 运行 时执行,而不是在构造 Function
对象时执行,因为它具有动态特性。如果您确定所有传递的参数始终属于同一类型,则可以通过添加 TArg
泛型类型来静态强制执行。