C# Passing Function as Argument

295,615

Solution 1

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

Solution 2

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

Solution 3

public static T Runner<T>(Func<T> funcToRun)
{
    //Do stuff before running function as normal
    return funcToRun();
}

Usage:

var ReturnValue = Runner(() => GetUser(99));
Share:
295,615

Related videos on Youtube

Ash
Author by

Ash

Updated on March 22, 2022

Comments

  • Ash
    Ash over 2 years

    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.

  • Joel Mueller
    Joel Mueller almost 14 years
    In .NET 4, both Func and Action have been updated to allow for up to 16 parameters.
  • Ani
    Ani almost 14 years
    A really cool thing to do would be to return a Func<double, double> 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.
  • KeithS
    KeithS almost 14 years
    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<double,double> 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.
  • Ian Johnson
    Ian Johnson almost 14 years
    I would argue that the method prototype still makes the code more readable than the Func<x, y> - 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.
  • quentin-starin
    quentin-starin almost 14 years
    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.
  • Ian Johnson
    Ian Johnson almost 14 years
    @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
  • kdbanman
    kdbanman almost 9 years
    I'm curious, why the generic type parameter?
  • DermFrench
    DermFrench almost 9 years
    I'm getting this error: The type arguments for method 'Runner<T>(Func<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
  • kravits88
    kravits88 almost 9 years
    What's your "funcToRun" method signature?
  • Dan Chase
    Dan Chase almost 5 years
    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?
  • David Bandel
    David Bandel over 3 years
    This is a pretty abstruse example for someone unfamiliar with delegates. Was the lambda expression really necessary?