186 votes

C# Passer une fonction comme argument

J'ai écrit une fonction en C# qui effectue une différenciation numérique. Cela ressemble à ceci :

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

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

Je voudrais pouvoir passer dans n'importe quelle fonction, comme dans :

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

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

Je pense que cela est possible avec les délégués (peut-être ?) mais je ne suis pas sûr de savoir comment les utiliser.

1 votes

Cela répond-il à votre question ? Passer la méthode comme paramètre en utilisant C#

203voto

qes Points 11681

Il existe quelques types génériques dans .Net (à partir de la version 2) qui facilitent le passage de fonctions en tant que délégués.

Pour les fonctions avec type de retour, il y a Func<> et pour les fonctions sans type de retour, il y a Action<>.

Func et Action peuvent être déclarés pour prendre de 0 à 4 paramètres. Par exemple, Func < double, int > prend un double comme paramètre et retourne un int. Action < double, double, double > prend trois doubles comme paramètres et ne retourne rien (void).

Ainsi, vous pouvez déclarer votre fonction Diff comme prenant un Func :

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

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

Puis vous l'appelez ainsi, en lui donnant simplement le nom de la fonction qui correspond à la signature de votre Func ou Action :

double result = Diff(myValue, Function);

Vous pouvez même écrire la fonction en ligne avec la syntaxe lambda :

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

33 votes

Dans .NET 4, les deux Func y Action ont été mis à jour pour permettre jusqu'à 16 paramètres.

5 votes

Une chose vraiment cool à faire serait de renvoyer une Func<double, double> qui est la dérivée première de la fonction d'entrée, calculée numériquement bien sûr. return x => (f(x + h) - f(x)) / h; Vous pourriez même écrire une surcharge qui renverrait la valeur n dérivée de la fonction d'entrée.

182voto

Ian Johnson Points 825

L'utilisation du Func comme mentionné ci-dessus fonctionne mais il existe également des délégués qui effectuent la même tâche et définissent également l'intention dans le nommage :

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

7 votes

Dans les versions 3.5 et suivantes, les Func<> et les délégués sont interchangeables, ce qui signifie que les délégués anonymes et les lambdas (qui sont un sucre syntaxique pour les délégués anonymes) peuvent également être utilisés. Ainsi, il importe peu que vous spécifiez le paramètre comme un Func<double,double> ou un délégué qui prend un double et renvoie un double. Le seul avantage réel qu'un délégué nommé vous donne est la possibilité d'ajouter des commentaires xml-doc ; les noms descriptifs sont tout aussi faciles à mettre en œuvre que le nom du paramètre au lieu du type.

6 votes

Je dirais que le prototype de méthode rend toujours le code plus lisible que le Func<x, y> - ce n'est pas seulement le nommage qui rend le code lisible et comme vous le dites, cela ne vous empêche pas de passer des lambdas dans le code.

0 votes

Si la dénomination du type de délégué est si importante pour la clarté du code, je pense que dans la plupart des cas, je pencherais pour une interface et des implémentations.

23voto

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

Utilisation :

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

1 votes

Je suis curieux, pourquoi le paramètre de type générique ?

4 votes

J'obtiens cette erreur : Les arguments de type pour la méthode 'Runner<T>(Func<T>)' ne peuvent pas être déduits de l'utilisation. Essayez de spécifier les arguments de type explicitement.

0 votes

Quelle est la signature de votre méthode "funcToRun" ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X