Passando uma função (com parâmetros) como um parâmetro?
-
03-07-2019 - |
Pergunta
Eu quero criar um genérico para que eu possa passar uma função como um parâmetro, no entanto esta função pode incluir parâmetros em si tão ...
int foo = GetCachedValue("LastFoo", methodToGetFoo)
Tal que:
protected int methodToGetFoo(DateTime today)
{ return 2; // example only }
Essencialmente eu quero ter um método que irá verificar a cache para um valor, caso contrário, irá gerar o valor com base no passado no método.
Os pensamentos?
Solução
Parece que você quer um 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;
}
O chamador pode, em seguida, enrole isso de várias maneiras; para funções simples:
int i = GetCachedValue("Foo", GetNextValue);
...
int GetNextValue() {...}
ou em que argumentos estão envolvidos, um fechamento:
var bar = ...
int i = GetCachedValue("Foo", () => GetNextValue(bar));
Outras dicas
Usando System.Action e expressão lambda (método anonimous). Por exemplo
public void myMethod(int integer){
//Do something
}
public void passFunction(System.Action methodWithParameters){
//Invoke
methodWithParameters();
}
//...
//Pass anonimous method using lambda expression
passFunction(() => myMethod(1234));
Você pode criar seu próprio delegado, mas em C # 3.0 você pode achar que é mais conveniente usar o built-in Func<T>
família delegado para resolver este problema. Exemplo:
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 vai levar três argumentos: uma corda, um int, e uma função que leva um DateTime e retorna um int. Por exemplo:
int foo = GetCachedValue("blah", 5, methodToGetFoo); // using your method
int bar = GetCachedValue("fuzz", 1, d => d.TotalDays); // using a lambda
Existem diferentes Func<T, U, V...>
etc. tipos no quadro para acomodar métodos com diferentes quantidades de argumentos.
Criar um delegado para o methodToGetFoo
método
public delegate object GenerateValue(params p);
public event GenerateValue OnGenerateValue;
Definir GetCachedValue usar o delegado
int GetCachedValue(string key, GenerateValue functionToCall);
Em seguida, na implementação de OnGenerateValue você pode verificar do param.
Aqui é algo simples Comecei que pode ser levado um pouco mais longe (como eu fiz para um projeto comercial).
No meu caso isso era para chamadas de serviço Web Cache, e foi usado algo como:
WebService ws = new WebService();
var result = ws.Call( x => x.Foo("bar", 1)); // x is the ws instance