Passer une fonction (avec des paramètres) en paramètre?
-
03-07-2019 - |
Question
Je souhaite créer un générique auquel je peux transmettre une fonction en tant que paramètre. Toutefois, cette fonction peut inclure des paramètres elle-même, de manière à ce que ...
int foo = GetCachedValue("LastFoo", methodToGetFoo)
Tels que:
protected int methodToGetFoo(DateTime today)
{ return 2; // example only }
Je veux essentiellement une méthode qui vérifie le cache pour une valeur, sinon elle va générer la valeur en fonction de la méthode transmise.
Pensées?
La solution
On dirait que vous voulez un Func<T>
:
T GetCachedValue<T>(string key, Func<T> method) {
T value;
if(!cache.TryGetValue(key, out value)) {
value = method();
cache[key] = value;
}
return value;
}
L’appelant peut ensuite envelopper le message de différentes façons. pour des fonctions simples:
int i = GetCachedValue("Foo", GetNextValue);
...
int GetNextValue() {...}
ou lorsque des arguments sont impliqués, une fermeture:
var bar = ...
int i = GetCachedValue("Foo", () => GetNextValue(bar));
Autres conseils
Utilisation de System.Action et de l'expression lambda (méthode anonyme). Par exemple
public void myMethod(int integer){
//Do something
}
public void passFunction(System.Action methodWithParameters){
//Invoke
methodWithParameters();
}
//...
//Pass anonimous method using lambda expression
passFunction(() => myMethod(1234));
Vous pouvez créer votre propre délégué, mais en C # 3.0, il peut s'avérer plus pratique d'utiliser la famille de délégués Func<T>
intégrée pour résoudre ce problème. Exemple:
public int GetCachedValue(string p1, int p2,
Func<DateTime, int> getCachedValue)
{
// do some stuff in here
// you can call getCachedValue like any normal function from within here
}
Cette méthode prendra trois arguments: une chaîne, un int et une fonction qui prend un DateTime et retourne un int. Par exemple:
int foo = GetCachedValue("blah", 5, methodToGetFoo); // using your method
int bar = GetCachedValue("fuzz", 1, d => d.TotalDays); // using a lambda
Différents types Func<T, U, V...>
etc. existent dans le cadre pour prendre en charge les méthodes avec différentes quantités d'arguments.
Créer un délégué pour la méthode methodToGetFoo
public delegate object GenerateValue(params p);
public event GenerateValue OnGenerateValue;
Définissez GetCachedValue pour utiliser le délégué
int GetCachedValue(string key, GenerateValue functionToCall);
Ensuite, dans l'implémentation de OnGenerateValue, vous pouvez vérifier les paramètres.
Voici quelque chose de simple, j'ai commencé cela peut être poussé un peu plus loin (comme je l’ai fait pour un projet commercial).
Dans mon cas, cela consistait à mettre en cache les appels de service Web et a été utilisé comme suit:
WebService ws = new WebService();
var result = ws.Call( x => x.Foo("bar", 1)); // x is the ws instance