2009-03-02 12 views
20

Je veux créer un générique auquel je peux passer une fonction comme paramètre, mais cette fonction peut comprendre lui-même les paramètres si ...Passer une fonction (avec paramètres) en paramètre?

int foo = GetCachedValue("LastFoo", methodToGetFoo) 

tel que:

protected int methodToGetFoo(DateTime today) 
{ return 2; // example only } 

Essentiellement, je veux avoir une méthode qui vérifiera le cache pour une valeur, sinon générera la valeur basée sur la méthode passée.

Pensées?

+0

Je ne sais pas comment faire cela, mais comme une note, cette question ne semble pas avoir quoi que ce soit à voir avec les génériques pour autant que je sache. – recursive

+0

C'est un peu un peu, peut-être. Probablement "délégués" devraient remplacer "génériques". – mquander

+0

Désolé, j'étais en train de créer une méthode générique pour gérer ça, donc j'ai supposé que c'était lié. Mais le passage est vraiment lié aux délégués, donc je vais mettre à jour. Merci – klkitchens

Répondre

37

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 alors envelopper de plusieurs 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)); 
+1

Merci, j'étais très proche, mais je ne pouvais pas comprendre comment obtenir les paramètres dans le générique.La dernière option, avec la fermeture était la clé! Fonctionne comme un charme. – klkitchens

+2

Vraiment vieux ici, mais la partie de fermeture était juste ce que je cherchais –

4

Vous pouvez créer votre propre délégué, mais en C# 3.0, vous pouvez trouver plus pratique d'utiliser le haut- Func<T> déléguer la famille 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 prend trois arguments: une chaîne, un int, et une fonction qui prend un DateTime et retourne un entier. 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 tenir compte des méthodes avec différentes quantités d'arguments.

3

Créer un délégué pour la méthode methodToGetFoo

public delegate object GenerateValue(params p); 
public event GenerateValue OnGenerateValue; 

Définir GetCachedValue utiliser le délégué

int GetCachedValue(string key, GenerateValue functionToCall); 

Puis, dans la mise en œuvre de OnGenerateValue vous pouvez vérifier les années param.

2

Here est quelque chose de simple que j'ai commencé et qui peut être pris un peu plus loin (comme je l'ai fait pour un projet commercial).

Dans mon cas, ce fut de mettre en cache les appels de service Web, et a été utilisé quelque chose comme:

WebService ws = new WebService(); 
var result = ws.Call(x => x.Foo("bar", 1)); // x is the ws instance 
7

En utilisant System.Action et expression lambda (méthode anonimous). 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)); 
Questions connexes