The only Func<...>/Action<...> delegate that is similar to WaitCallback is Action<object>. It won't be directly usable; however, you can wrap delegates inside eachother:
Action<object> func = // TODO
ThreadPool.QueueUserWorkItem(state=>func(state));
To return a result, one option is to update external state. Lambdas / anon-methods are good for this, since they offer closure support:
Func<int, int> func = x => x * 5;
int query = 4, result = 0;
ThreadPool.QueueUserWorkItem(state=> {
result = func(query);
});
After execution, result (from the above context) will be updated. However, a callback is more common:
Func<int, int> func = x => x * 5;
int query = 4;
Action<int> callback = x =>
{
Console.WriteLine(x);
};
ThreadPool.QueueUserWorkItem(state=> {
int result = func(query);
callback(result);
});
Where the callback function does something useful with the result.
Hopefully that also shows how you can execute arbitrary functions in a thread-pool thread.
Re synchronization; you are on a secondary thread, so you definitely would need synchronization if talking to any shared state. However, you might choose to use the UI to synchronize the result (if suitable) - i.e. (from a winform):
ThreadPool.QueueUserWorkItem(state => {
// now on worker thread
int result = ... // TODO
this.Invoke((Action)delegate {
// now on UI thread
this.Text = result.ToString();
});
});