sydd sydd - 2 months ago 5
C# Question

Passing a generic method as a parameter in C#

I am trying to write a function, that takes another function as a parameter (and the calls it later) I know that its doable if I know the signature of the function beforehand, but is this possible, if I dont?
For example:

// 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);
}


EDIT: I do not want to assume anything about
functionToCallLater
It can look like these for example:

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

Answer

Do you mean like this? :

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

You have object[] as your values, but I'm assuming that you want to specify their type as well using a generic. Also, since it didn't look like your method you are calling doesn't have a return type, I used Action<T> instead of Func<T>.

Based on the comment below,

If you want to accept different signatures, you really have 2 different options. The first like SLaks said is to use reflection. This can get extremely complicated though, as you're going to have to determine the position and types of the parameters in the functionToCallLater, and line those up with the incoming parameters from the parent function. There are a lot of semantics that really make this difficult (although it is possible) and really more trouble than it's worse when the problem is generalized to handle a large number of cases.

A second and more verifiable way of handling this scenario (although not necessarily less work), is to create overloads for the method in question:

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.

Depending on how complicated the method to overload is, this may be slightly tedious to almost impossible, but it will work. The real question you want to ask yourself in this scenario is, "Is this the optimal way to handle this approach?" For example, if you don't need a return value in the calling method, why allow one at all? You can always force the caller to wrap the function in another method which adheres to the method signature like so:

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

This removes some of the scenarios and functionality the method needs to handle. By reducing the possible options the method signature needs to handle, the problem becomes simpler and more manageable.