180

I've written a function in C# that does a numerical differentiation. It looks like this:

public double Diff(double x)
{
    double h = 0.0000001;

    return (Function(x + h) - Function(x)) / h;
}

I would like to be able to pass in any function, as in:

public double Diff(double x, function f)
{
    double h = 0.0000001;

    return (f(x + h) - f(x)) / h;
}

I think this is possible with delegates (maybe?) but I'm not sure how to use them.

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Ash
  • 3,279
  • 4
  • 28
  • 26
  • 1
    Does this answer your question? [Pass Method as Parameter using C#](https://stackoverflow.com/questions/2082615/pass-method-as-parameter-using-c-sharp) – Davide Cannizzo Aug 23 '20 at 13:12

3 Answers3

198

There are a couple generic types in .Net (v2 and later) that make passing functions around as delegates very easy.

For functions with return types, there is Func<> and for functions without return types there is Action<>.

Both Func and Action can be declared to take from 0 to 4 parameters. For example, Func < double, int > takes one double as a parameter and returns an int. Action < double, double, double > takes three doubles as parameters and returns nothing (void).

So you can declare your Diff function to take a Func:

public double Diff(double x, Func<double, double> f) {
    double h = 0.0000001;

    return (f(x + h) - f(x)) / h;
}

And then you call it as so, simply giving it the name of the function that fits the signature of your Func or Action:

double result = Diff(myValue, Function);

You can even write the function in-line with lambda syntax:

double result = Diff(myValue, d => Math.Sqrt(d * 3.14));
quentin-starin
  • 26,121
  • 7
  • 68
  • 86
  • 32
    In .NET 4, both `Func` and `Action` have been updated to allow for [up to 16](http://msdn.microsoft.com/en-us/library/dd402862.aspx) parameters. – Joel Mueller Sep 01 '10 at 21:26
  • 5
    A really cool thing to do would be to return a `Func` that is the first-derivative of the input function, numerically calculated of course. `return x => (f(x + h) - f(x)) / h;` You could even write an overload that returned the `n` th derivative of the input function. – Ani Sep 01 '10 at 21:49
179

Using the Func as mentioned above works but there are also delegates that do the same task and also define intent within the naming:

public delegate double MyFunction(double x);

public double Diff(double x, MyFunction f)
{
    double h = 0.0000001;

    return (f(x + h) - f(x)) / h;
}

public double MyFunctionMethod(double x)
{
    // Can add more complicated logic here
    return x + 10;
}

public void Client()
{
    double result = Diff(1.234, x => x * 456.1234);
    double secondResult = Diff(2.345, MyFunctionMethod);
}
Ian Johnson
  • 2,224
  • 1
  • 13
  • 9
  • 7
    In 3.5 and later, Func<>s and delegates are interchangeable, and that means that anonymous delegates and lambdas (which are syntactic sugar for anonymous delegates) can also be used. So it doesn't really matter whether you specify the parameter as a Func or a delegate that takes a double and returns a double. The only real advantage a named delegate gives you is the ability to add xml-doc comments; descriptive names are just as easy to implement as the parameter name instead of the type. – KeithS Sep 01 '10 at 22:51
  • 6
    I would argue that the method prototype still makes the code more readable than the Func - it is not just the naming that makes code readable and as you say that does not stop you from passing lambdas into the code. – Ian Johnson Sep 01 '10 at 23:13
  • If the naming of the delegate type is so important to code clarity, I think in most cases I'd be leaning towards an interface and implementations. – quentin-starin Sep 02 '10 at 03:09
  • @qstarin it is not just the naming of the delegate but the naming of the arguments that the method must take, especially if they are just native types. You are right, mostly I use interfaces over delegates – Ian Johnson Sep 02 '10 at 10:26
  • If I'm making one of these as a common function that provides common functionality, (with a not-so-common return type) everything works until I try to use it with void. Do I really need to make a duplicate function using Action instead of Func or is there a better way? – Dan Chase Jul 15 '19 at 20:37
  • This is a pretty abstruse example for someone unfamiliar with delegates. Was the lambda expression really necessary? – David Bandel Jan 14 '21 at 11:46
22
public static T Runner<T>(Func<T> funcToRun)
{
    //Do stuff before running function as normal
    return funcToRun();
}

Usage:

var ReturnValue = Runner(() => GetUser(99));
kravits88
  • 12,431
  • 1
  • 51
  • 53