views:

634

answers:

4

I want to create a generic to which I can pass a function as a parameter, however this function may include parameters itself so...

int foo = GetCachedValue("LastFoo", methodToGetFoo)

Such that:

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

Essentially I want to have a method that will check the cache for a value, otherwise will generate the value based on the passed in method.

Thoughts?

+12  A: 

It sounds like you want a 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;
}

The caller can then wrap this in many ways; for simple functions:

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

or where arguments are involved, a closure:

var bar = ...
int i = GetCachedValue("Foo", () => GetNextValue(bar));
Marc Gravell
Thanks I was very close, but could not figure how to get the parms right in the generic. The last option, with the closure was the key! Works like a charm.
peiklk
+2  A: 

You can create your own delegate, but in C# 3.0 you may find it more convenient to use the built-in Func<T> delegate family to solve this problem. Example:

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
}

This method will take three arguments: a string, an int, and a function that takes a DateTime and returns an int. For example:

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. types exist in the framework to accommodate methods with different amounts of arguments.

mquander
+1  A: 

Create a delegate for the method methodToGetFoo

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

Define GetCachedValue to use the delegate

int GetCachedValue(string key, GenerateValue functionToCall);

Then in the implementation of OnGenerateValue you can check the param's.

Dead account
+1  A: 

Here is something simple I started that can be taken a bit further (as I did for a commercial project).

In my case this was to cache web service calls, and was used something like:

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