Передача функции (с параметрами) в качестве параметра?

Я хочу создать универсальный, которому я могу передать функцию в качестве параметра, однако эта функция может включать в себя сами параметры, поэтому...

int foo = GetCachedValue("LastFoo", methodToGetFoo)

Такой, что:

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

По сути, я хочу иметь метод, который будет проверять кеш на наличие значения, иначе будет генерировать значение на основе переданного метода.

Мысли?


person klkitchens    schedule 02.03.2009    source источник
comment
Я не знаю, как это сделать, но, насколько я могу судить, этот вопрос не имеет ничего общего с дженериками.   -  person recursive    schedule 03.03.2009
comment
Это как-то так, немного, может быть. Вероятно, делегаты должны заменить дженерики.   -  person mqp    schedule 03.03.2009
comment
Извините, я создавал общий метод для обработки этого, поэтому я вроде как предположил, что это связано. Но передача действительно связана с делегированием, поэтому я обновлю. Спасибо   -  person klkitchens    schedule 03.03.2009


Ответы (5)


Похоже, вы хотите 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;
}

Затем вызывающая сторона может обернуть это разными способами; для простых функций:

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

или, если задействованы аргументы, замыкание:

var bar = ...
int i = GetCachedValue("Foo", () => GetNextValue(bar));
person Marc Gravell    schedule 02.03.2009
comment
Спасибо, я был очень близок, но не мог понять, как правильно получить пармы в универсальном. Последний вариант, с замыканием был ключ! Работает как шарм. - person klkitchens; 03.03.2009
comment
Действительно старый здесь, но часть закрытия была именно тем, что я искал - person Fredrik Stolpe; 20.08.2015

Используйте System.Action и лямбда-выражение (анонимный метод). Например:

public void myMethod(int integer) {     
    // Do something
}

public void passFunction(System.Action methodWithParameters) {
    // Invoke
    methodWithParameters();
}

// ...

// Pass anonymous method using lambda expression
passFunction(() => myMethod(1234));
person empirico gutierrez    schedule 28.10.2014
comment
Я правильно понимаю, () => myMethod(1234) оборачивает параметризованный метод в непараметризованный метод в качестве возвращаемого значения? - person aDoubleSo; 24.05.2019

Вы можете создать свой собственный делегат, но в C# 3.0 вам может быть удобнее использовать встроенное семейство делегатов Func<T> для решения этой проблемы. Пример:

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
}

Этот метод будет принимать три аргумента: строку, целое число и функцию, которая принимает DateTime и возвращает целое число. Например:

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

В фреймворке существуют разные типы Func<T, U, V...> и т. д. для размещения методов с разным количеством аргументов.

person mqp    schedule 02.03.2009

Создайте делегат для метода methodToGetFoo

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

Определите GetCachedValue для использования делегата

int GetCachedValue(string key, GenerateValue functionToCall);

Затем в реализации OnGenerateValue вы можете проверить параметры.

person Dead account    schedule 02.03.2009

здесь я начал что-то простое, что может быть немного дальше (как я сделал для коммерческого проекта).

В моем случае это было для кэширования вызовов веб-службы и использовалось примерно так:

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