Skip to content

Instantly share code, notes, and snippets.

@shoover
Created November 3, 2010 13:13
Show Gist options
  • Save shoover/661058 to your computer and use it in GitHub Desktop.
Save shoover/661058 to your computer and use it in GitHub Desktop.
wraps an action in an asynchronous Post on the current synchronization context
// usage:
// // In a UI event handler:
// BarAsync(result => label.Text = result);
//
// void BarAsync(Action<int> completed) {
// completed = completed.Marshal();
// ThreadPool.QueueUserWorkItem(() => completed(42));
// }
//
// Here's what it replaces. You'd need one of these for each delegate type
// you want to Marshal (Action, Action<T1,T2>, WaitCallback, etc).
// public static Action<T> Marshal<T>(this Action<T> self)
// {
// var sync = SynchronizationContext.Current;
// if (sync == null)
// {
// return self;
// }
// return t => sync.Post(state => self(t), null);
// }
public static class ActionExt
{
/// <summary>
/// Returns a delegate that invokes action in a Post on the current syncronization context.
/// </summary>
public static T MarshalAction<T>(this T action) // the compiler doesn't allow "where T:Delegate"
{
Debug.Assert(action is Delegate);
var invoke = action.GetType().GetMethod("Invoke");
Debug.Assert(invoke.ReturnType == typeof(void));
var sync = SynchronizationContext.Current;
if (sync == null)
{
return action;
}
var args = invoke.GetParameters().Select(p => Expression.Parameter(p.ParameterType, p.Name)).
ToArray();
var poster = Expression.Lambda<T>(
Expression.Call(
Expression.Constant(sync),
typeof(SynchronizationContext).GetMethod("Post"),
Expression.Lambda<SendOrPostCallback>(
Expression.Invoke(Expression.Constant(action), args),
Expression.Parameter(typeof(object), "ignore")),
Expression.Constant(null)),
args);
return poster.Compile();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment