【问题标题】:How to wrap a Func<T1...Tn> with unknown number and type of parameters in C#?如何在 C# 中用未知数量和类型的参数包装 Func<T1...Tn>?
【发布时间】:2023-03-29 16:50:01
【问题描述】:

假设我有这个类:

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&lt;float&gt;,而是Func&lt;float, float&gt;Func&lt;float, float, float&gt;等。

我一直在寻找FuncdelegateAction,但仍然没有弄清楚如何拥有这个可以容纳和执行具有不同数量参数的函数的“函数胶囊”。为简单起见,我认为唯一的输入和输出类型是float

我正在考虑使用 Func&lt;List&lt;float&gt;&gt; 之类的东西,但我想知道是否有更好的选择。

【问题讨论】:

  • 好吧,Func&lt;float&gt; 只是返回一个浮点数。看起来您的 Function 实例将存储参数列表.. 那么为什么不使用无参数委托(您拥有;Func&lt;float&gt;)并在其闭包中使用 argv
  • 即:this.f = delegate() { return Math.Pow(this.argv[0], this.argv[1])};
  • 它给了我一个错误this.f is a type but it's used as a variable。我将f 声明为public delegate float f();,并在构造函数中编写了与您发送的代码相同的代码。
  • 对不起,试试这个。我错过了一个分号和一个演员表:this.f = delegate() { return (float)Math.Pow(this.argv[0], this.argv[1]);}; (REPL)
  • f 保留为public Func&lt;float&gt; f;

标签: c# delegates func


【解决方案1】:

我想提出一个更准确地符合 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 泛型类型来静态强制执行。

【讨论】:

  • 这确实是一个很好的解决方案。你认为我可以扩展它以接受任何类型的参数,而不仅仅是双打吗?
  • 我编辑了我的帖子以允许任何类型或参数,并通过为Function 添加 TReturn 泛型来指定返回类型。您可以将其留给object,但这样您就可以进行最少的类型检查。
猜你喜欢
  • 2014-12-17
  • 2022-01-16
  • 2016-03-10
  • 1970-01-01
  • 2014-05-15
  • 2015-11-11
  • 2011-05-20
  • 2020-09-13
  • 1970-01-01
相关资源
最近更新 更多