С# Передача функции в качестве аргумента

Я написал функцию на С#, которая выполняет численное дифференцирование. Это выглядит так:

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

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

Я хотел бы иметь возможность передавать любую функцию, как в:

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

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

Я думаю, что это возможно с делегатами (может быть?), но я не уверен, как их использовать.

Любая помощь будет принята с благодарностью.

Ответ 1

Использование Func, как упомянуто выше, работает, но есть также делегаты, которые выполняют одну и ту же задачу, а также определяют намерение в именовании:

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

Ответ 2

В .Net(v2 и более поздних) существует несколько общих типов, которые упрощают выполнение функций передачи в виде делегатов.

Для функций с возвращаемыми типами существует Func < > и для функций без типов возврата есть Action < > .

Оба Func и Action могут быть объявлены как от 0 до 4 параметров. Например, Func < double, int > принимает один двойной параметр и возвращает int. Действие < double, double, double > принимает три удвоения в качестве параметров и ничего не возвращает (void).

Итак, вы можете объявить, что ваша функция Diff принимает Func:

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

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

И тогда вы называете это так, просто указывая ему имя функции, которая соответствует сигнатуре вашего Func или Action:

double result = Diff(myValue, Function);

Вы можете даже написать функцию в строке с синтаксисом лямбда:

double result = Diff(myValue, d => Math.Sqrt(d * 3.14));

Ответ 3

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

Использование:

var ReturnValue = Runner(() => GetUser(99));