Skip to content

Instantly share code, notes, and snippets.

@phatboyg
Created July 26, 2012 23:11
Show Gist options
  • Save phatboyg/3185165 to your computer and use it in GitHub Desktop.
Save phatboyg/3185165 to your computer and use it in GitHub Desktop.
Method Async Proxy
using System;
public interface IProxyAsyncResult<T> :
IAsyncResult
{
T Result { get; }
}
using System;
using System.Linq.Expressions;
public static class Proxy<T>
where T : class
{
public static Proxy<T,TResult> Create<TResult>(Expression<Func<T, TResult>> targetExpression)
{
var methodCallExpression = targetExpression.Body as MethodCallExpression;
if (methodCallExpression == null)
throw new ArgumentException("The target must be a member expression", "targetExpression");
var method = methodCallExpression.Method;
if (method == null)
throw new ArgumentException("The target could not be cast to a member", "targetExpression");
var call = targetExpression.Compile();
return new Proxy<T, TResult>(call);
}
}
public class Proxy<T, TResult>
where T : class
{
readonly Func<T, TResult> _call;
public Proxy(Func<T, TResult> call)
{
_call = call;
}
public IAsyncResult BeginCall(T target, AsyncCallback callback, object state)
{
var asyncProxy = new ProxyAsyncResult<T, TResult>(target, _call, callback, state);
return asyncProxy;
}
public TResult EndCall(IAsyncResult asyncResult)
{
var asyncProxy = asyncResult as IProxyAsyncResult<TResult>;
if(asyncProxy == null)
throw new ArgumentException("The result was not an async proxy", "asyncResult");
return asyncProxy.Result;
}
}
using System;
using System.Threading;
public class ProxyAsyncResult<T, TResult> :
IProxyAsyncResult<TResult>
where T : class
{
readonly Func<T, TResult> _call;
readonly AsyncCallback _callback;
readonly object _state;
readonly T _target;
volatile bool _complete;
ManualResetEvent _event;
Exception _exception;
TResult _result;
public ProxyAsyncResult(T target, Func<T, TResult> call, AsyncCallback callback, object state)
{
_target = target;
_call = call;
_callback = callback;
_state = state;
ThreadPool.QueueUserWorkItem(Run, this);
}
public bool IsCompleted
{
get { return _complete; }
}
public WaitHandle AsyncWaitHandle
{
get
{
lock (this)
{
if (_event == null)
_event = new ManualResetEvent(_complete);
}
return _event;
}
}
public object AsyncState
{
get { return _state; }
}
public bool CompletedSynchronously
{
get { return false; }
}
TResult IProxyAsyncResult<TResult>.Result
{
get
{
if (_exception != null)
throw _exception;
return _result;
}
}
void Run(object state)
{
try
{
_result = _call(_target);
}
catch (Exception ex)
{
_exception = ex;
}
finally
{
Complete();
}
}
void Complete()
{
try
{
_complete = true;
if (_callback != null)
{
_callback(this);
}
lock (this)
{
if (_event != null)
_event.Set();
}
}
catch (Exception)
{
// this sucks, but what can we do?
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment