2009-03-02 56 views
20

Quiero crear una genérica a la que me puedo pasar una función como un parámetro, sin embargo, esta función puede incluir parámetros en sí por lo ...Pasar una función (con parámetros) como parámetro?

int foo = GetCachedValue("LastFoo", methodToGetFoo) 

tal que:

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

Esencialmente quiero tener un método que verificará el valor en caché, de lo contrario generará el valor según el método aprobado.

¿Pensamientos?

+0

No sé cómo hacer esto, pero como nota, esta pregunta no parece tener nada que ver con los genéricos, por lo que puedo ver. – recursive

+0

Es algo que hace, un poco, tal vez. Probablemente los "delegados" deberían reemplazar a los "genéricos". – mquander

+0

Lo siento, estaba creando un método genérico para manejar esto, así que supuse que estaba relacionado. Pero el paso es realmente relacionado con el delegado, así que lo actualizaré. Gracias – klkitchens

Respuesta

37

Parece que usted quiere una 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; 
} 

La persona que llama puede entonces terminar con esto de muchas maneras; para funciones simples:

int i = GetCachedValue("Foo", GetNextValue); 
... 
int GetNextValue() {...} 

o cuando se trata de argumentos, un cierre:

var bar = ... 
int i = GetCachedValue("Foo",() => GetNextValue(bar)); 
+1

Gracias estuve muy cerca, pero no pude entender cómo obtener los parms en el genérico.La última opción, con el cierre fue la clave! Funciona de maravilla. – klkitchens

+2

Realmente viejo aquí, pero la parte de cierre fue justo lo que estaba buscando –

4

Usted puede crear su propio delegado, pero en C# 3.0 puede que le resulte más conveniente utilizar el built-in Func<T> familia de delegados para resolver este problema. Ejemplo:

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 
} 

Este método se llevará a tres argumentos: una cadena, un int, y una función que toma un DateTime y devuelve un int. Por ejemplo: existen

int foo = GetCachedValue("blah", 5, methodToGetFoo); // using your method 
int bar = GetCachedValue("fuzz", 1, d => d.TotalDays); // using a lambda 

Different Func<T, U, V...> etc. tipos en el marco para acomodar métodos con diferentes cantidades de argumentos.

3

Crear un delegado para el método methodToGetFoo

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

Definir GetCachedValue utilizar el delegado

int GetCachedValue(string key, GenerateValue functionToCall); 

Luego, en la implementación de OnGenerateValue puede comprobar la década de param.

2

Here es algo simple que comencé que se puede llevar un poco más allá (como lo hice para un proyecto comercial).

En mi caso esto fue para almacenar en caché las llamadas de servicio web, y se utilizó algo como:

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

Usando System.Action y expresión lambda (método anónimo). Por ejemplo

public void myMethod(int integer){ 

    //Do something 

} 

public void passFunction(System.Action methodWithParameters){ 

    //Invoke 
    methodWithParameters(); 

} 

//... 

//Pass anonimous method using lambda expression 
passFunction(() => myMethod(1234)); 
Cuestiones relacionadas