如何根据参数的数量将变量参数传递给调用特定函数的函数?

时间:2018-06-18 18:59:28

标签: c# parameters

这是How do I pass a function pointer delegate for a different class in c#

的后续问题

我有一个班级

public class ClassA
{
    public void Foo()
    {
        Console.WriteLine("Foo()");
    }
    public void Foo(int x, int y)
    {
        Console.WriteLine("Foo(" + x.ToString() + ", " + y.ToString()  + ")" );
    }
    public void Foo(int x, int y, int z)
    {
        Console.WriteLine("Foo(" + x.ToString() + ", " + y.ToString() + ", " + z.ToString() + ")" );
    }
}

在另一种方法中,我想像这样调用classA的类函数:

ClassA obj = new ClassA();
TakesFun(obj.Foo);
TakesFun(obj.Foo, 1, 2);
TakesFun(obj.Foo, 1, 2, 3);

TakesFun的语法应该是什么?我想把它变成泛型来接受很多/ any / none参数并根据参数的数量调用适当的函数?

显然下面的函数语法是错误的,但我正在寻找一个类似的函数。

public static void TakesFun<TParam>(Action<TParam[]> action, params TParam[] paramList)
{
    Console.WriteLine("TakesFun");
    action(paramList);
}

EDIT1:ClassA Foo函数只是一个例子。我想调用更复杂的函数,可以采取任何形式的论证。 喜欢例如:

public void CleanList(List<int> l)
{
    l.Clear();
}

1 个答案:

答案 0 :(得分:6)

  

在另一种方法中,我想像这样调用classA的类函数:       TakesFun(obj.Foo);

接下来请注意,TakesFun是一个采用Action的方法,而不是一组重载方法。

你无法得到你想要的东西,你必须学会​​忍受失望。 C#不支持您想要的功能。

您正在将obj.Foo方法组表单转换为委托表单,这需要C#执行重载解析通过将TakesFun的形式参数列表中的委托与名为Foo的方法集合进行比较,然后选择最佳方法。

因为没有最好的&#34;在编译时,这将失败。

找到解决问题的另一种方法。 你的问题听起来非常像我们称之为&#34; XY问题&#34;。也就是说,你有一些真正的问题,你对如何解决它有一个疯狂的想法永远不会有效,现在你问一个关于你疯狂想法的问题。问一个关于真正问题的问题。几乎可以肯定,有一种比这更好的解决方法。

现在,如果我们放松一些问题的限制,那么我们就可以做到。特别是,如果我们放宽只有一个TakesFun并且它是可变参数的约束,那么我们就可以做到。我注意到TakesFun实际上是函数应用程序操作:

static void Apply(Action action) => action();
static void Apply<A>(Action<A> action, A a) => action(a);
static void Apply<A, B>(Action<A, B> action, A a, B b) => action(a, b);
static void Apply<A, B, C>(Action<A, B, C> action, A a, B b, C c) => action(a, b, c);
... and so on, as many as you need

现在重载决议的魔力解决了你的问题:

Apply(obj.Foo, 1, 2, 3); // Works fine

重载决议推断Apply表示Apply<int, int, int>ActionAction<int, int, int>,而Foo表示采用三个整数。

C#类型推断非常好,但你必须在我们设计成语言的范围内使用它。

更新:根据您的评论,听起来您正在尝试重新创建任务并行库。我会调查TPL,看看它是否已满足您的需求。

在C#中,我们代表将来作为Task执行的工作单元的概念;有一个巨大的库和内置语言支持,用于组合任务中的工作流程,将其延续安排到各种线程,等等。 使用此作品而非尝试自己发明

例如,如果您想要创建代表未来工作的未启动任务,您可以这样做:

static Task TaskFactory(Action action) => new Task(action);
static Task TaskFactory<A>(Action<A> action, A a) => new Task(()=>action(a));
static Task TaskFactory<A, B>(Action<A, B> action, A a, B b) => new Task(()=>action(a, b));

等等。现在你可以做到:

Task t = TaskFactory(obj.Foo, 1, 2);

并获取t 启动时将执行操作。然后,您可以说出任务完成后您想要发生的事情:

t.ContinueWith(task => Console.WriteLine("Task complete!"));

然后启动它:

t.Start();

有一些机制可用于创建已在工作线程上启动和运行的任务。有一些机制用于调度任务或其完成以在特定线程上运行。等等;这是一个巨大的主题。如果您对此有疑问,请提出其他问题。