2009-03-02 12 views
20

Chcę stworzyć ogólny, do których mogę przekazać funkcję jako parametr, jednak funkcja ta może obejmować sama więc parametry ...Przekazywanie funkcji (z parametrami) jako parametru?

int foo = GetCachedValue("LastFoo", methodToGetFoo) 

taka, że:

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

zasadniczo chcę mieć metodę, która sprawdzi pamięć podręczną dla wartości, w przeciwnym razie wygeneruje wartość na podstawie przekazanej metody.

Myśli?

+0

Nie wiem, jak to zrobić, ale na marginesie to pytanie wydaje się nie mieć nic wspólnego z rodzajami, o ile wiem. – recursive

+0

Może trochę, trochę. Prawdopodobnie "delegaci" powinni zastąpić "generics". – mquander

+0

Niestety, tworzyłem ogólną metodę radzenia sobie z tym, więc założyłem, że było to powiązane. Ale przekazanie jest naprawdę związane z delegatem, więc zaktualizuję. Dzięki – klkitchens

Odpowiedz

37

Brzmi jak chcesz 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; 
} 

Dzwoniący może następnie owinąć to na wiele sposobów; do prostych funkcji:

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

lub gdzie zaangażowane są argumenty, zamknięcie:

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

Dzięki, byłem bardzo blisko, ale nie mogłem wymyślić, jak uzyskać parm w prawo.Ostatnia opcja, z zamknięciem, była kluczem! Działa jak marzenie. – klkitchens

+2

Naprawdę stary tutaj, ale zamknięcie było tym, czego szukałem –

4

Można utworzyć własny delegata, ale w C# 3.0 może okazać się wygodniejsze w użyciu wbudowanego Func<T> Przekaż rodzinę, aby rozwiązać ten problem. Przykład:

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 
} 

Metoda ta będzie miała trzy argumenty: ciąg, int, a funkcja, która zajmuje DateTime i zwraca int. Np istnieje

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

różne Func<T, U, V...> itp typów w ramach celu dostosowania metod z różnymi ilościami argumentów.

3

Tworzenie delegata dla metody methodToGetFoo

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

Definiowanie GetCachedValue używać pełnomocnikowi

int GetCachedValue(string key, GenerateValue functionToCall); 

Następnie w realizacji OnGenerateValue można sprawdzić param tych.

2

Here jest czymś prostym zacząłem, które mogą być brane kawałek dalej (jak ja do projektu komercyjnego).

W moim przypadku było to buforować połączenia usług internetowych, a użyto coś takiego:

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

Korzystanie System.Action i wyrażenia lambda (metoda anonimowi). Na przykład:

public void myMethod(int integer){ 

    //Do something 

} 

public void passFunction(System.Action methodWithParameters){ 

    //Invoke 
    methodWithParameters(); 

} 

//... 

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