Vorbei an einer Funktion (mit Parametern) als Parameter?
-
03-07-2019 - |
Frage
Ich möchte eine generisch zu schaffen, an dem ich eine Funktion als Parameter übergeben kann, jedoch kann diese Funktion Parameter umfassen selbst so ...
int foo = GetCachedValue("LastFoo", methodToGetFoo)
So, dass:
protected int methodToGetFoo(DateTime today)
{ return 2; // example only }
Im Grunde möchte ich eine Methode haben, die den Cache auf einen Wert geprüft werden, andernfalls wird der Wert erzeugen auf der Basis der in-Methode übergeben.
Die Gedanken?
Lösung
Es klingt wie Sie eine Func<T>
wollen:
T GetCachedValue<T>(string key, Func<T> method) {
T value;
if(!cache.TryGetValue(key, out value)) {
value = method();
cache[key] = value;
}
return value;
}
Der Anrufer kann dann diese wickelt in vielerlei Hinsicht; für einfache Funktionen:
int i = GetCachedValue("Foo", GetNextValue);
...
int GetNextValue() {...}
oder wo Argumente beteiligt sind, eine Schließung:
var bar = ...
int i = GetCachedValue("Foo", () => GetNextValue(bar));
Andere Tipps
Mit System.Action und Lambda-Ausdruck (anonimous Methode). Zum Beispiel
public void myMethod(int integer){
//Do something
}
public void passFunction(System.Action methodWithParameters){
//Invoke
methodWithParameters();
}
//...
//Pass anonimous method using lambda expression
passFunction(() => myMethod(1234));
Sie können Ihren eigenen Delegierten, aber in C # 3.0 erstellen Sie finden es bequemer, die sich im internen Func<T>
delegieren Familie zu lösen dieses Problem zu verwenden. Beispiel:
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
}
Diese Methode drei Argumente: ein String, ein int, und eine Funktion, die eine Datetime nimmt ab und gibt einen int. Zum Beispiel:
int foo = GetCachedValue("blah", 5, methodToGetFoo); // using your method
int bar = GetCachedValue("fuzz", 1, d => d.TotalDays); // using a lambda
Verschiedene Func<T, U, V...>
usw. Typen existieren im Rahmen Methoden mit unterschiedlichen Mengen von Argumenten gerecht zu werden.
Erstellen Sie einen Delegaten für die Methode methodToGetFoo
public delegate object GenerateValue(params p);
public event GenerateValue OnGenerateValue;
definieren GetCachedValue die Delegaten verwenden
int GetCachedValue(string key, GenerateValue functionToCall);
Dann bei der Umsetzung der OnGenerateValue können Sie den param der überprüfen.
Hier ist ich etwas einfach gestartet das kann ein bisschen weiter genommen werden (wie ich für ein kommerzielles Projekt tat).
In meinem Fall war die Web-Service-Aufruf cachen, und wurde so etwas wie verwendet:
WebService ws = new WebService();
var result = ws.Call( x => x.Foo("bar", 1)); // x is the ws instance