Question

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?

Was it helpful?

Solution

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 = GetCachedValue("Foo", GetNextValue);
...
int GetNextValue() {...}

or where arguments are involved, a closure:

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

OTHER TIPS

Using System.Action and lambda expression(anonimous method). For example

    public void myMethod(int integer){

    //Do something

}

public void passFunction(System.Action methodWithParameters){

    //Invoke
    methodWithParameters();

}

//...

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

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.

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.

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top