将通用方法作为参数传递给C#

时间:2016-09-25 22:49:50

标签: c# methods delegates

我正在尝试编写一个函数,它将另一个函数作为参数(稍后调用)我知道如果我知道signature of the function beforehand它是可行的,但这是否可能,如果我不这样做? (比如在JavaScript中将函数作为参数传递)

例如:

// this should accept a function with any kind of signature and return value
void DelayedCall(?? functionToCallLater, float delayInSecs, params object[] values)
{
    //here do something like (just as an example)
    functionToCallLater.Invoke(values);
}

编辑:我不想假设有关functionToCallLater的任何内容。例如,它可能看起来像这样:

    int MyFunc()
    void MyFunc2()
    void MyFunc3(int someParam) 
    string MyFunc4(int someParam, MyClass someOtherParam) 
    void MyFunc5<T>(params T[] values) 

3 个答案:

答案 0 :(得分:2)

如果您对该功能一无所知,则需要使用Reflection(并支付性能损失)。

让它接受Delegate,然后致电.DynamicInvoke()

答案 1 :(得分:1)

你是说这个意思吗? :

void DelayedCall<T>(Action<T> functionToCallLater, 
  float delayInSecs, params T[] values)
{
    //here do something like (just as an example)
    functionToCallLater(values);
}

你有对象[]作为你的值,但我假设你想要使用泛型来指定它们的类型。此外,由于您调用的方法看起来不像返回类型,因此我使用Action<T>代替Func<T>

根据以下评论,

如果您想接受不同的签名,您确实有2种不同的选项。第一个像SLaks说的是使用反射。这可能会变得非常复杂,因为您将不得不确定functionToCallLater中参数的位置和类型,并将这些参数与父函数中的传入参数对齐。有许多语义确实使这很困难(尽管有可能),并且当问题被广泛用于处理大量案例时,实际上更麻烦。

处理此场景的第二种更可验证的方法(尽管不一定少工作)是为相关方法创建重载:

void DelayedCall<T>(Func<T> functionToCallLater, 
      float delayInSecs, params T[] values)

void DelayedCall<T,R>(Func<T,R> functionToCallLater, 
      float delayInSecs, params T[] values)

void DelayedCall<T>(Func<T,X,R> functionToCallLater, 
      float delayInSecs, params T[] values)

etc.

根据重载方法的复杂程度,这可能稍微繁琐到几乎不可能,但它会起作用。在这种情况下,您想要问自己的真正问题是,“这是处理这种方法的最佳方式吗?”例如,如果您在调用方法中不需要返回值,为什么要允许一个?您总是可以强制调用者将函数包装在另一个遵循方法签名的方法中,如下所示:

void DelayedCall<T>(Action<T> functionToCallLater, 
      float delayInSecs, params T[] values)
....
 DelayledCallAction<int>(
    (i) => MyMethodWhichReturnsSomething(i), 
    floadDelayInSecs, 1,2,3);

这将删除方法需要处理的一些方案和功能。通过减少方法签名需要处理的可能选项,问题变得更简单,更易于管理。

答案 2 :(得分:0)

我认为这在C#:/

中会非常冗长

这是一个可以接受返回或不返回值并接受0 - 2参数的函数的解决方案:

    // signature: void MyFunc()
    void DelayedCall(Action sdf, float delayInSecs)
    {
    }

    // signature: SomeClass MyFunc()
    void DelayedCall<T>(Func<T> sdf, float delayInSecs)
    {
    }

    // signature: void MyFunc(SomeClass param1)
    void DelayedCall<T>(Action<T> sdf, float delayInSecs, T values)
    {
    }

    // signature: SomeClass MyFunc(SomeClass param1)
    void DelayedCall<T, K>(Func<T, K> sdf, float delayInSecs, T values)
    {
    }

    // signature: void MyFunc(SomeClass param1, SomeClass2 param2)
    void DelayedCall<T, K>(Action<T, K> sdf, float delayInSecs, T values, K values2)
    {
    }

    // signature: SomeClass MyFunc(SomeClass param1, SomeClass2 param2)
    void DelayedCall<T, K, L>(Func<T, K, L> sdf, float delayInSecs, T values, K values2)
    {
    }

这些接受例如以下内容:

    void MyFunc1() {  }
    int MyFunc2() { return 6; }
    void MyFunc3(int someParam) { }
    string MyFunc4(string someParam) { return "";  }
    void MyFunc5(int someParam, string someparam2) { }
    string MyFunc6(string someParam, int someparam2) { return "";  }